blob: 7c0c7d09e089dc8d6074402f527e678e7727cb98 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/block/floppy.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 * Copyright (C) 1993, 1994 Alain Knaff
6 * Copyright (C) 1998 Alan Cox
7 */
Jesper Juhl06f748c2007-10-16 23:30:57 -07008
Linus Torvalds1da177e2005-04-16 15:20:36 -07009/*
10 * 02.12.91 - Changed to static variables to indicate need for reset
11 * and recalibrate. This makes some things easier (output_byte reset
12 * checking etc), and means less interrupt jumping in case of errors,
13 * so the code is hopefully easier to understand.
14 */
15
16/*
17 * This file is certainly a mess. I've tried my best to get it working,
18 * but I don't like programming floppies, and I have only one anyway.
19 * Urgel. I should check for more errors, and do more graceful error
20 * recovery. Seems there are problems with several drives. I've tried to
21 * correct them. No promises.
22 */
23
24/*
25 * As with hd.c, all routines within this file can (and will) be called
26 * by interrupts, so extreme caution is needed. A hardware interrupt
27 * handler may not sleep, or a kernel panic will happen. Thus I cannot
28 * call "floppy-on" directly, but have to set a special timer interrupt
29 * etc.
30 */
31
32/*
33 * 28.02.92 - made track-buffering routines, based on the routines written
34 * by entropy@wintermute.wpi.edu (Lawrence Foard). Linus.
35 */
36
37/*
38 * Automatic floppy-detection and formatting written by Werner Almesberger
39 * (almesber@nessie.cs.id.ethz.ch), who also corrected some problems with
40 * the floppy-change signal detection.
41 */
42
43/*
44 * 1992/7/22 -- Hennus Bergman: Added better error reporting, fixed
45 * FDC data overrun bug, added some preliminary stuff for vertical
46 * recording support.
47 *
48 * 1992/9/17: Added DMA allocation & DMA functions. -- hhb.
49 *
50 * TODO: Errors are still not counted properly.
51 */
52
53/* 1992/9/20
54 * Modifications for ``Sector Shifting'' by Rob Hooft (hooft@chem.ruu.nl)
55 * modeled after the freeware MS-DOS program fdformat/88 V1.8 by
56 * Christoph H. Hochst\"atter.
57 * I have fixed the shift values to the ones I always use. Maybe a new
58 * ioctl() should be created to be able to modify them.
59 * There is a bug in the driver that makes it impossible to format a
60 * floppy as the first thing after bootup.
61 */
62
63/*
64 * 1993/4/29 -- Linus -- cleaned up the timer handling in the kernel, and
65 * this helped the floppy driver as well. Much cleaner, and still seems to
66 * work.
67 */
68
69/* 1994/6/24 --bbroad-- added the floppy table entries and made
70 * minor modifications to allow 2.88 floppies to be run.
71 */
72
73/* 1994/7/13 -- Paul Vojta -- modified the probing code to allow three or more
74 * disk types.
75 */
76
77/*
78 * 1994/8/8 -- Alain Knaff -- Switched to fdpatch driver: Support for bigger
79 * format bug fixes, but unfortunately some new bugs too...
80 */
81
82/* 1994/9/17 -- Koen Holtman -- added logging of physical floppy write
83 * errors to allow safe writing by specialized programs.
84 */
85
86/* 1995/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks
87 * by defining bit 1 of the "stretch" parameter to mean put sectors on the
88 * opposite side of the disk, leaving the sector IDs alone (i.e. Commodore's
89 * drives are "upside-down").
90 */
91
92/*
93 * 1995/8/26 -- Andreas Busse -- added Mips support.
94 */
95
96/*
97 * 1995/10/18 -- Ralf Baechle -- Portability cleanup; move machine dependent
98 * features to asm/floppy.h.
99 */
100
101/*
James Nelsonb88b0982005-11-08 16:52:12 +0100102 * 1998/1/21 -- Richard Gooch <rgooch@atnf.csiro.au> -- devfs support
103 */
104
105/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 * 1998/05/07 -- Russell King -- More portability cleanups; moved definition of
107 * interrupt and dma channel to asm/floppy.h. Cleaned up some formatting &
108 * use of '0' for NULL.
109 */
110
111/*
112 * 1998/06/07 -- Alan Cox -- Merged the 2.0.34 fixes for resource allocation
113 * failures.
114 */
115
116/*
117 * 1998/09/20 -- David Weinehall -- Added slow-down code for buggy PS/2-drives.
118 */
119
120/*
121 * 1999/08/13 -- Paul Slootman -- floppy stopped working on Alpha after 24
122 * days, 6 hours, 32 minutes and 32 seconds (i.e. MAXINT jiffies; ints were
123 * being used to store jiffies, which are unsigned longs).
124 */
125
126/*
127 * 2000/08/28 -- Arnaldo Carvalho de Melo <acme@conectiva.com.br>
128 * - get rid of check_region
129 * - s/suser/capable/
130 */
131
132/*
133 * 2001/08/26 -- Paul Gortmaker - fix insmod oops on machines with no
134 * floppy controller (lingering task on list after module is gone... boom.)
135 */
136
137/*
138 * 2002/02/07 -- Anton Altaparmakov - Fix io ports reservation to correct range
139 * (0x3f2-0x3f5, 0x3f7). This fix is a bit of a hack but the proper fix
140 * requires many non-obvious changes in arch dependent code.
141 */
142
143/* 2003/07/28 -- Daniele Bellucci <bellucda@tiscali.it>.
144 * Better audit of register_blkdev.
145 */
146
147#define FLOPPY_SANITY_CHECK
148#undef FLOPPY_SILENT_DCL_CLEAR
149
150#define REALLY_SLOW_IO
151
152#define DEBUGT 2
Joe Perches48c8cee2010-03-10 15:20:45 -0800153#define DCL_DEBUG /* debug disk change line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
155/* do print messages for unexpected interrupts */
156static int print_unex = 1;
157#include <linux/module.h>
158#include <linux/sched.h>
159#include <linux/fs.h>
160#include <linux/kernel.h>
161#include <linux/timer.h>
162#include <linux/workqueue.h>
163#define FDPATCHES
164#include <linux/fdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165#include <linux/fd.h>
166#include <linux/hdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167#include <linux/errno.h>
168#include <linux/slab.h>
169#include <linux/mm.h>
170#include <linux/bio.h>
171#include <linux/string.h>
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800172#include <linux/jiffies.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173#include <linux/fcntl.h>
174#include <linux/delay.h>
175#include <linux/mc146818rtc.h> /* CMOS defines */
176#include <linux/ioport.h>
177#include <linux/interrupt.h>
178#include <linux/init.h>
Russell Kingd052d1b2005-10-29 19:07:23 +0100179#include <linux/platform_device.h>
Scott James Remnant83f9ef42009-04-02 16:56:47 -0700180#include <linux/mod_devicetable.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181#include <linux/buffer_head.h> /* for invalidate_buffers() */
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800182#include <linux/mutex.h>
Joe Perchesd4937542010-03-10 15:20:44 -0800183#include <linux/io.h>
184#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185
186/*
187 * PS/2 floppies have much slower step rates than regular floppies.
188 * It's been recommended that take about 1/4 of the default speed
189 * in some more extreme cases.
190 */
191static int slow_floppy;
192
193#include <asm/dma.h>
194#include <asm/irq.h>
195#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
197static int FLOPPY_IRQ = 6;
198static int FLOPPY_DMA = 2;
199static int can_use_virtual_dma = 2;
200/* =======
201 * can use virtual DMA:
202 * 0 = use of virtual DMA disallowed by config
203 * 1 = use of virtual DMA prescribed by config
204 * 2 = no virtual DMA preference configured. By default try hard DMA,
205 * but fall back on virtual DMA when not enough memory available
206 */
207
208static int use_virtual_dma;
209/* =======
210 * use virtual DMA
211 * 0 using hard DMA
212 * 1 using virtual DMA
213 * This variable is set to virtual when a DMA mem problem arises, and
214 * reset back in floppy_grab_irq_and_dma.
215 * It is not safe to reset it in other circumstances, because the floppy
216 * driver may have several buffers in use at once, and we do currently not
217 * record each buffers capabilities
218 */
219
220static DEFINE_SPINLOCK(floppy_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221
222static unsigned short virtual_dma_port = 0x3f0;
David Howells7d12e782006-10-05 14:55:46 +0100223irqreturn_t floppy_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224static int set_dor(int fdc, char mask, char data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
226#define K_64 0x10000 /* 64KB */
227
228/* the following is the mask of allowed drives. By default units 2 and
229 * 3 of both floppy controllers are disabled, because switching on the
230 * motor of these drives causes system hangs on some PCI computers. drive
231 * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
232 * a drive is allowed.
233 *
234 * NOTE: This must come before we include the arch floppy header because
235 * some ports reference this variable from there. -DaveM
236 */
237
238static int allowed_drive_mask = 0x33;
239
240#include <asm/floppy.h>
241
242static int irqdma_allocated;
243
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244#define DEVICE_NAME "floppy"
245
246#include <linux/blkdev.h>
247#include <linux/blkpg.h>
248#include <linux/cdrom.h> /* for the compatibility eject ioctl */
249#include <linux/completion.h>
250
251static struct request *current_req;
252static struct request_queue *floppy_queue;
Joe Perches48c8cee2010-03-10 15:20:45 -0800253static void do_fd_request(struct request_queue *q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
255#ifndef fd_get_dma_residue
256#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
257#endif
258
259/* Dma Memory related stuff */
260
261#ifndef fd_dma_mem_free
262#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
263#endif
264
265#ifndef fd_dma_mem_alloc
Joe Perches48c8cee2010-03-10 15:20:45 -0800266#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL, get_order(size))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267#endif
268
269static inline void fallback_on_nodma_alloc(char **addr, size_t l)
270{
271#ifdef FLOPPY_CAN_FALLBACK_ON_NODMA
272 if (*addr)
273 return; /* we have the memory */
274 if (can_use_virtual_dma != 2)
275 return; /* no fallback allowed */
Joe Perchesb46df352010-03-10 15:20:46 -0800276 pr_info("DMA memory shortage. Temporarily falling back on virtual DMA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 *addr = (char *)nodma_mem_alloc(l);
278#else
279 return;
280#endif
281}
282
283/* End dma memory related stuff */
284
285static unsigned long fake_change;
286static int initialising = 1;
287
Joe Perches48c8cee2010-03-10 15:20:45 -0800288#define ITYPE(x) (((x) >> 2) & 0x1f)
289#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
290#define UNIT(x) ((x) & 0x03) /* drive on fdc */
291#define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700292 /* reverse mapping from unit and fdc to drive */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
Joe Perches48c8cee2010-03-10 15:20:45 -0800295#define DP (&drive_params[current_drive])
296#define DRS (&drive_state[current_drive])
297#define DRWE (&write_errors[current_drive])
298#define FDCS (&fdc_state[fdc])
299#define CLEARF(x) clear_bit(x##_BIT, &DRS->flags)
300#define SETF(x) set_bit(x##_BIT, &DRS->flags)
301#define TESTF(x) test_bit(x##_BIT, &DRS->flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
Joe Perches48c8cee2010-03-10 15:20:45 -0800303#define UDP (&drive_params[drive])
304#define UDRS (&drive_state[drive])
305#define UDRWE (&write_errors[drive])
306#define UFDCS (&fdc_state[FDC(drive)])
307#define UCLEARF(x) clear_bit(x##_BIT, &UDRS->flags)
308#define USETF(x) set_bit(x##_BIT, &UDRS->flags)
309#define UTESTF(x) test_bit(x##_BIT, &UDRS->flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Joe Perches48c8cee2010-03-10 15:20:45 -0800311#define DPRINT(format, args...) \
Joe Perchesb46df352010-03-10 15:20:46 -0800312 pr_info(DEVICE_NAME "%d: " format, current_drive, ##args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
Joe Perches48c8cee2010-03-10 15:20:45 -0800314#define PH_HEAD(floppy, head) (((((floppy)->stretch & 2) >> 1) ^ head) << 2)
315#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
316
317#define CLEARSTRUCT(x) memset((x), 0, sizeof(*(x)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
319/* read/write */
Joe Perches48c8cee2010-03-10 15:20:45 -0800320#define COMMAND (raw_cmd->cmd[0])
321#define DR_SELECT (raw_cmd->cmd[1])
322#define TRACK (raw_cmd->cmd[2])
323#define HEAD (raw_cmd->cmd[3])
324#define SECTOR (raw_cmd->cmd[4])
325#define SIZECODE (raw_cmd->cmd[5])
326#define SECT_PER_TRACK (raw_cmd->cmd[6])
327#define GAP (raw_cmd->cmd[7])
328#define SIZECODE2 (raw_cmd->cmd[8])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329#define NR_RW 9
330
331/* format */
Joe Perches48c8cee2010-03-10 15:20:45 -0800332#define F_SIZECODE (raw_cmd->cmd[2])
333#define F_SECT_PER_TRACK (raw_cmd->cmd[3])
334#define F_GAP (raw_cmd->cmd[4])
335#define F_FILL (raw_cmd->cmd[5])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336#define NR_F 6
337
338/*
Joe Perches48c8cee2010-03-10 15:20:45 -0800339 * Maximum disk size (in kilobytes).
340 * This default is used whenever the current disk size is unknown.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 * [Now it is rather a minimum]
342 */
343#define MAX_DISK_SIZE 4 /* 3984 */
344
345/*
346 * globals used by 'result()'
347 */
348#define MAX_REPLIES 16
349static unsigned char reply_buffer[MAX_REPLIES];
350static int inr; /* size of reply buffer, when called from interrupt */
Joe Perches48c8cee2010-03-10 15:20:45 -0800351#define ST0 (reply_buffer[0])
352#define ST1 (reply_buffer[1])
353#define ST2 (reply_buffer[2])
354#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
355#define R_TRACK (reply_buffer[3])
356#define R_HEAD (reply_buffer[4])
357#define R_SECTOR (reply_buffer[5])
358#define R_SIZECODE (reply_buffer[6])
359
360#define SEL_DLY (2 * HZ / 100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
362/*
363 * this struct defines the different floppy drive types.
364 */
365static struct {
366 struct floppy_drive_params params;
367 const char *name; /* name printed while booting */
368} default_drive_params[] = {
369/* NOTE: the time values in jiffies should be in msec!
370 CMOS drive type
371 | Maximum data rate supported by drive type
372 | | Head load time, msec
373 | | | Head unload time, msec (not used)
374 | | | | Step rate interval, usec
375 | | | | | Time needed for spinup time (jiffies)
376 | | | | | | Timeout for spinning down (jiffies)
377 | | | | | | | Spindown offset (where disk stops)
378 | | | | | | | | Select delay
379 | | | | | | | | | RPS
380 | | | | | | | | | | Max number of tracks
381 | | | | | | | | | | | Interrupt timeout
382 | | | | | | | | | | | | Max nonintlv. sectors
383 | | | | | | | | | | | | | -Max Errors- flags */
384{{0, 500, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 80, 3*HZ, 20, {3,1,2,0,2}, 0,
385 0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },
386
387{{1, 300, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 40, 3*HZ, 17, {3,1,2,0,2}, 0,
388 0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
389
390{{2, 500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0,
391 0, { 2, 5, 6,23,10,20,12, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/
392
393{{3, 250, 16, 16, 3000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
394 0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/
395
396{{4, 500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
397 0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/
398
399{{5, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
400 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
401
402{{6, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
403 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*/
404/* | --autodetected formats--- | | |
405 * read_track | | Name printed when booting
406 * | Native format
407 * Frequency of disk change checks */
408};
409
410static struct floppy_drive_params drive_params[N_DRIVE];
411static struct floppy_drive_struct drive_state[N_DRIVE];
412static struct floppy_write_errors write_errors[N_DRIVE];
413static struct timer_list motor_off_timer[N_DRIVE];
414static struct gendisk *disks[N_DRIVE];
415static struct block_device *opened_bdev[N_DRIVE];
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800416static DEFINE_MUTEX(open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
418
419/*
420 * This struct defines the different floppy types.
421 *
422 * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
423 * types (e.g. 360kB diskette in 1.2MB drive, etc.). Bit 1 of 'stretch'
424 * tells if the disk is in Commodore 1581 format, which means side 0 sectors
425 * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
426 * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
427 * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
428 * side 0 is on physical side 0 (but with the misnamed sector IDs).
429 * 'stretch' should probably be renamed to something more general, like
Keith Wansbrough9e491842008-09-22 14:57:17 -0700430 * 'options'.
431 *
432 * Bits 2 through 9 of 'stretch' tell the number of the first sector.
433 * The LSB (bit 2) is flipped. For most disks, the first sector
434 * is 1 (represented by 0x00<<2). For some CP/M and music sampler
435 * disks (such as Ensoniq EPS 16plus) it is 0 (represented as 0x01<<2).
436 * For Amstrad CPC disks it is 0xC1 (represented as 0xC0<<2).
437 *
438 * Other parameters should be self-explanatory (see also setfdprm(8)).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 */
440/*
441 Size
442 | Sectors per track
443 | | Head
444 | | | Tracks
445 | | | | Stretch
446 | | | | | Gap 1 size
447 | | | | | | Data rate, | 0x40 for perp
448 | | | | | | | Spec1 (stepping rate, head unload
449 | | | | | | | | /fmt gap (gap2) */
450static struct floppy_struct floppy_type[32] = {
451 { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* 0 no testing */
452 { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360" }, /* 1 360KB PC */
453 { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" }, /* 2 1.2MB AT */
454 { 720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360" }, /* 3 360KB SS 3.5" */
455 { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720" }, /* 4 720KB 3.5" */
456 { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360" }, /* 5 360KB AT */
457 { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" }, /* 6 720KB AT */
458 { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /* 7 1.44MB 3.5" */
459 { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /* 8 2.88MB 3.5" */
460 { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" }, /* 9 3.12MB 3.5" */
461
462 { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */
463 { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */
464 { 820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410" }, /* 12 410KB 5.25" */
465 { 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820" }, /* 13 820KB 3.5" */
466 { 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" }, /* 14 1.48MB 5.25" */
467 { 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" }, /* 15 1.72MB 3.5" */
468 { 840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420" }, /* 16 420KB 5.25" */
469 { 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830" }, /* 17 830KB 3.5" */
470 { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" }, /* 18 1.49MB 5.25" */
471 { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5" */
472
473 { 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880" }, /* 20 880KB 5.25" */
474 { 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5" */
475 { 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5" */
476 { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25" */
477 { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5" */
478 { 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5" */
479 { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5" */
480 { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5" */
481 { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5" */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5" */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700483
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */
485 { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */
486};
487
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488#define SECTSIZE (_FD_SECTSIZE(*floppy))
489
490/* Auto-detection: Disk type used until the next media change occurs. */
491static struct floppy_struct *current_type[N_DRIVE];
492
493/*
494 * User-provided type information. current_type points to
495 * the respective entry of this array.
496 */
497static struct floppy_struct user_params[N_DRIVE];
498
499static sector_t floppy_sizes[256];
500
Hannes Reinecke94fd0db2005-07-15 10:09:25 +0200501static char floppy_device_name[] = "floppy";
502
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503/*
504 * The driver is trying to determine the correct media format
505 * while probing is set. rw_interrupt() clears it after a
506 * successful access.
507 */
508static int probing;
509
510/* Synchronization of FDC access. */
Joe Perches48c8cee2010-03-10 15:20:45 -0800511#define FD_COMMAND_NONE -1
512#define FD_COMMAND_ERROR 2
513#define FD_COMMAND_OKAY 3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
515static volatile int command_status = FD_COMMAND_NONE;
516static unsigned long fdc_busy;
517static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
518static DECLARE_WAIT_QUEUE_HEAD(command_done);
519
520#define NO_SIGNAL (!interruptible || !signal_pending(current))
Joe Perches48c8cee2010-03-10 15:20:45 -0800521#define CALL(x) if ((x) == -EINTR) return -EINTR
522#define ECALL(x) if ((ret = (x))) return ret;
523#define _WAIT(x,i) CALL(ret=wait_til_done((x),i))
524#define WAIT(x) _WAIT((x),interruptible)
525#define IWAIT(x) _WAIT((x),1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
527/* Errors during formatting are counted here. */
528static int format_errors;
529
530/* Format request descriptor. */
531static struct format_descr format_req;
532
533/*
534 * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
535 * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
536 * H is head unload time (1=16ms, 2=32ms, etc)
537 */
538
539/*
540 * Track buffer
541 * Because these are written to by the DMA controller, they must
542 * not contain a 64k byte boundary crossing, or data will be
543 * corrupted/lost.
544 */
545static char *floppy_track_buffer;
546static int max_buffer_sectors;
547
548static int *errors;
Jesper Juhl06f748c2007-10-16 23:30:57 -0700549typedef void (*done_f)(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550static struct cont_t {
Joe Perches48c8cee2010-03-10 15:20:45 -0800551 void (*interrupt)(void);
552 /* this is called after the interrupt of the
553 * main command */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700554 void (*redo)(void); /* this is called to retry the operation */
555 void (*error)(void); /* this is called to tally an error */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 done_f done; /* this is called to say if the operation has
557 * succeeded/failed */
558} *cont;
559
560static void floppy_ready(void);
561static void floppy_start(void);
562static void process_fd_request(void);
563static void recalibrate_floppy(void);
564static void floppy_shutdown(unsigned long);
565
Philippe De Muyter5a74db02009-02-18 14:48:36 -0800566static int floppy_request_regions(int);
567static void floppy_release_regions(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568static int floppy_grab_irq_and_dma(void);
569static void floppy_release_irq_and_dma(void);
570
571/*
572 * The "reset" variable should be tested whenever an interrupt is scheduled,
573 * after the commands have been sent. This is to ensure that the driver doesn't
574 * get wedged when the interrupt doesn't come because of a failed command.
575 * reset doesn't need to be tested before sending commands, because
576 * output_byte is automatically disabled when reset is set.
577 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578static void reset_fdc(void);
579
580/*
581 * These are global variables, as that's the easiest way to give
582 * information to interrupts. They are the data used for the current
583 * request.
584 */
Joe Perches48c8cee2010-03-10 15:20:45 -0800585#define NO_TRACK -1
586#define NEED_1_RECAL -2
587#define NEED_2_RECAL -3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
589static int usage_count;
590
591/* buffer related variables */
592static int buffer_track = -1;
593static int buffer_drive = -1;
594static int buffer_min = -1;
595static int buffer_max = -1;
596
597/* fdc related variables, should end up in a struct */
598static struct floppy_fdc_state fdc_state[N_FDC];
599static int fdc; /* current fdc */
600
601static struct floppy_struct *_floppy = floppy_type;
602static unsigned char current_drive;
603static long current_count_sectors;
604static unsigned char fsector_t; /* sector in track */
605static unsigned char in_sector_offset; /* offset within physical sector,
606 * expressed in units of 512 bytes */
607
608#ifndef fd_eject
609static inline int fd_eject(int drive)
610{
611 return -EINVAL;
612}
613#endif
614
615/*
616 * Debugging
617 * =========
618 */
619#ifdef DEBUGT
620static long unsigned debugtimer;
621
622static inline void set_debugt(void)
623{
624 debugtimer = jiffies;
625}
626
627static inline void debugt(const char *message)
628{
629 if (DP->flags & DEBUGT)
Joe Perchesb46df352010-03-10 15:20:46 -0800630 pr_info("%s dtime=%lu\n", message, jiffies - debugtimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631}
632#else
633static inline void set_debugt(void) { }
634static inline void debugt(const char *message) { }
635#endif /* DEBUGT */
636
637typedef void (*timeout_fn) (unsigned long);
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700638static DEFINE_TIMER(fd_timeout, floppy_shutdown, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
640static const char *timeout_message;
641
642#ifdef FLOPPY_SANITY_CHECK
643static void is_alive(const char *message)
644{
645 /* this routine checks whether the floppy driver is "alive" */
646 if (test_bit(0, &fdc_busy) && command_status < 2
647 && !timer_pending(&fd_timeout)) {
648 DPRINT("timeout handler died: %s\n", message);
649 }
650}
651#endif
652
Joe Perches48c8cee2010-03-10 15:20:45 -0800653static void (*do_floppy)(void) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
655#ifdef FLOPPY_SANITY_CHECK
656
657#define OLOGSIZE 20
658
Joe Perches48c8cee2010-03-10 15:20:45 -0800659static void (*lasthandler)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660static unsigned long interruptjiffies;
661static unsigned long resultjiffies;
662static int resultsize;
663static unsigned long lastredo;
664
665static struct output_log {
666 unsigned char data;
667 unsigned char status;
668 unsigned long jiffies;
669} output_log[OLOGSIZE];
670
671static int output_log_pos;
672#endif
673
674#define current_reqD -1
675#define MAXTIMEOUT -2
676
677static void __reschedule_timeout(int drive, const char *message, int marg)
678{
679 if (drive == current_reqD)
680 drive = current_drive;
681 del_timer(&fd_timeout);
Eric Sesterhenn / Snakebyte4acb3e22007-05-23 13:58:15 -0700682 if (drive < 0 || drive >= N_DRIVE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 fd_timeout.expires = jiffies + 20UL * HZ;
684 drive = 0;
685 } else
686 fd_timeout.expires = jiffies + UDP->timeout;
687 add_timer(&fd_timeout);
Joe Perchesa81ee542010-03-10 15:20:46 -0800688 if (UDP->flags & FD_DEBUG)
Joe Perchesb46df352010-03-10 15:20:46 -0800689 DPRINT("reschedule timeout %s %d\n", message, marg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 timeout_message = message;
691}
692
693static void reschedule_timeout(int drive, const char *message, int marg)
694{
695 unsigned long flags;
696
697 spin_lock_irqsave(&floppy_lock, flags);
698 __reschedule_timeout(drive, message, marg);
699 spin_unlock_irqrestore(&floppy_lock, flags);
700}
701
Joe Perches48c8cee2010-03-10 15:20:45 -0800702#define INFBOUND(a, b) (a) = max_t(int, a, b)
703#define SUPBOUND(a, b) (a) = min_t(int, a, b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
705/*
706 * Bottom half floppy driver.
707 * ==========================
708 *
709 * This part of the file contains the code talking directly to the hardware,
710 * and also the main service loop (seek-configure-spinup-command)
711 */
712
713/*
714 * disk change.
715 * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
716 * and the last_checked date.
717 *
718 * last_checked is the date of the last check which showed 'no disk change'
719 * FD_DISK_CHANGE is set under two conditions:
720 * 1. The floppy has been changed after some i/o to that floppy already
721 * took place.
722 * 2. No floppy disk is in the drive. This is done in order to ensure that
723 * requests are quickly flushed in case there is no disk in the drive. It
724 * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
725 * the drive.
726 *
727 * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
728 * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
729 * each seek. If a disk is present, the disk change line should also be
730 * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
731 * change line is set, this means either that no disk is in the drive, or
732 * that it has been removed since the last seek.
733 *
734 * This means that we really have a third possibility too:
735 * The floppy has been changed after the last seek.
736 */
737
738static int disk_change(int drive)
739{
740 int fdc = FDC(drive);
Jesper Juhl06f748c2007-10-16 23:30:57 -0700741
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742#ifdef FLOPPY_SANITY_CHECK
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800743 if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 DPRINT("WARNING disk change called early\n");
745 if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
746 (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
747 DPRINT("probing disk change on unselected drive\n");
748 DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
749 (unsigned int)FDCS->dor);
750 }
751#endif
752
753#ifdef DCL_DEBUG
754 if (UDP->flags & FD_DEBUG) {
755 DPRINT("checking disk change line for drive %d\n", drive);
756 DPRINT("jiffies=%lu\n", jiffies);
757 DPRINT("disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
758 DPRINT("flags=%lx\n", UDRS->flags);
759 }
760#endif
761 if (UDP->flags & FD_BROKEN_DCL)
762 return UTESTF(FD_DISK_CHANGED);
763 if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
764 USETF(FD_VERIFY); /* verify write protection */
765 if (UDRS->maxblock) {
766 /* mark it changed */
767 USETF(FD_DISK_CHANGED);
768 }
769
770 /* invalidate its geometry */
771 if (UDRS->keep_data >= 0) {
772 if ((UDP->flags & FTD_MSG) &&
773 current_type[drive] != NULL)
774 DPRINT("Disk type is undefined after "
775 "disk change\n");
776 current_type[drive] = NULL;
777 floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
778 }
779
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 return 1;
781 } else {
782 UDRS->last_checked = jiffies;
783 UCLEARF(FD_DISK_NEWCHANGE);
784 }
785 return 0;
786}
787
788static inline int is_selected(int dor, int unit)
789{
790 return ((dor & (0x10 << unit)) && (dor & 3) == unit);
791}
792
793static int set_dor(int fdc, char mask, char data)
794{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700795 unsigned char unit;
796 unsigned char drive;
797 unsigned char newdor;
798 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
800 if (FDCS->address == -1)
801 return -1;
802
803 olddor = FDCS->dor;
804 newdor = (olddor & mask) | data;
805 if (newdor != olddor) {
806 unit = olddor & 0x3;
807 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
808 drive = REVDRIVE(fdc, unit);
809#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -0800810 if (UDP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 DPRINT("calling disk change from set_dor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812#endif
813 disk_change(drive);
814 }
815 FDCS->dor = newdor;
816 fd_outb(newdor, FD_DOR);
817
818 unit = newdor & 0x3;
819 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
820 drive = REVDRIVE(fdc, unit);
821 UDRS->select_date = jiffies;
822 }
823 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 return olddor;
825}
826
827static void twaddle(void)
828{
829 if (DP->select_delay)
830 return;
831 fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
832 fd_outb(FDCS->dor, FD_DOR);
833 DRS->select_date = jiffies;
834}
835
836/* reset all driver information about the current fdc. This is needed after
837 * a reset, and after a raw command. */
838static void reset_fdc_info(int mode)
839{
840 int drive;
841
842 FDCS->spec1 = FDCS->spec2 = -1;
843 FDCS->need_configure = 1;
844 FDCS->perp_mode = 1;
845 FDCS->rawcmd = 0;
846 for (drive = 0; drive < N_DRIVE; drive++)
847 if (FDC(drive) == fdc && (mode || UDRS->track != NEED_1_RECAL))
848 UDRS->track = NEED_2_RECAL;
849}
850
851/* selects the fdc and drive, and enables the fdc's input/dma. */
852static void set_fdc(int drive)
853{
854 if (drive >= 0 && drive < N_DRIVE) {
855 fdc = FDC(drive);
856 current_drive = drive;
857 }
858 if (fdc != 1 && fdc != 0) {
Joe Perchesb46df352010-03-10 15:20:46 -0800859 pr_info("bad fdc value\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 return;
861 }
862 set_dor(fdc, ~0, 8);
863#if N_FDC > 1
864 set_dor(1 - fdc, ~8, 0);
865#endif
866 if (FDCS->rawcmd == 2)
867 reset_fdc_info(1);
868 if (fd_inb(FD_STATUS) != STATUS_READY)
869 FDCS->reset = 1;
870}
871
872/* locks the driver */
873static int _lock_fdc(int drive, int interruptible, int line)
874{
875 if (!usage_count) {
Joe Perchesb46df352010-03-10 15:20:46 -0800876 pr_err("Trying to lock fdc while usage count=0 at line %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 line);
878 return -1;
879 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
881 if (test_and_set_bit(0, &fdc_busy)) {
882 DECLARE_WAITQUEUE(wait, current);
883 add_wait_queue(&fdc_wait, &wait);
884
885 for (;;) {
886 set_current_state(TASK_INTERRUPTIBLE);
887
888 if (!test_and_set_bit(0, &fdc_busy))
889 break;
890
891 schedule();
892
893 if (!NO_SIGNAL) {
894 remove_wait_queue(&fdc_wait, &wait);
895 return -EINTR;
896 }
897 }
898
899 set_current_state(TASK_RUNNING);
900 remove_wait_queue(&fdc_wait, &wait);
Ingo Molnar3e541a42006-07-03 00:24:23 -0700901 flush_scheduled_work();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 }
903 command_status = FD_COMMAND_NONE;
904
905 __reschedule_timeout(drive, "lock fdc", 0);
906 set_fdc(drive);
907 return 0;
908}
909
Joe Perches48c8cee2010-03-10 15:20:45 -0800910#define lock_fdc(drive, interruptible) \
911 _lock_fdc(drive, interruptible, __LINE__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912
Joe Perches48c8cee2010-03-10 15:20:45 -0800913#define LOCK_FDC(drive, interruptible) \
914 if (lock_fdc(drive, interruptible)) \
915 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
917/* unlocks the driver */
918static inline void unlock_fdc(void)
919{
920 unsigned long flags;
921
922 raw_cmd = NULL;
923 if (!test_bit(0, &fdc_busy))
924 DPRINT("FDC access conflict!\n");
925
926 if (do_floppy)
927 DPRINT("device interrupt still active at FDC release: %p!\n",
928 do_floppy);
929 command_status = FD_COMMAND_NONE;
930 spin_lock_irqsave(&floppy_lock, flags);
931 del_timer(&fd_timeout);
932 cont = NULL;
933 clear_bit(0, &fdc_busy);
Tejun Heo9934c8c2009-05-08 11:54:16 +0900934 if (current_req || blk_peek_request(floppy_queue))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 do_fd_request(floppy_queue);
936 spin_unlock_irqrestore(&floppy_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 wake_up(&fdc_wait);
938}
939
940/* switches the motor off after a given timeout */
941static void motor_off_callback(unsigned long nr)
942{
943 unsigned char mask = ~(0x10 << UNIT(nr));
944
945 set_dor(FDC(nr), mask, 0);
946}
947
948/* schedules motor off */
949static void floppy_off(unsigned int drive)
950{
951 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700952 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
954 if (!(FDCS->dor & (0x10 << UNIT(drive))))
955 return;
956
957 del_timer(motor_off_timer + drive);
958
959 /* make spindle stop in a position which minimizes spinup time
960 * next time */
961 if (UDP->rps) {
962 delta = jiffies - UDRS->first_read_date + HZ -
963 UDP->spindown_offset;
964 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
965 motor_off_timer[drive].expires =
966 jiffies + UDP->spindown - delta;
967 }
968 add_timer(motor_off_timer + drive);
969}
970
971/*
972 * cycle through all N_DRIVE floppy drives, for disk change testing.
973 * stopping at current drive. This is done before any long operation, to
974 * be sure to have up to date disk change information.
975 */
976static void scandrives(void)
977{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700978 int i;
979 int drive;
980 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
982 if (DP->select_delay)
983 return;
984
985 saved_drive = current_drive;
986 for (i = 0; i < N_DRIVE; i++) {
987 drive = (saved_drive + i + 1) % N_DRIVE;
988 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
989 continue; /* skip closed drives */
990 set_fdc(drive);
991 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
992 (0x10 << UNIT(drive))))
993 /* switch the motor off again, if it was off to
994 * begin with */
995 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
996 }
997 set_fdc(saved_drive);
998}
999
1000static void empty(void)
1001{
1002}
1003
David Howells65f27f32006-11-22 14:55:48 +00001004static DECLARE_WORK(floppy_work, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005
Joe Perches48c8cee2010-03-10 15:20:45 -08001006static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007{
David Howells65f27f32006-11-22 14:55:48 +00001008 PREPARE_WORK(&floppy_work, (work_func_t)handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 schedule_work(&floppy_work);
1010}
1011
Ingo Molnar8d06afa2005-09-09 13:10:40 -07001012static DEFINE_TIMER(fd_timer, NULL, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013
1014static void cancel_activity(void)
1015{
1016 unsigned long flags;
1017
1018 spin_lock_irqsave(&floppy_lock, flags);
1019 do_floppy = NULL;
David Howells65f27f32006-11-22 14:55:48 +00001020 PREPARE_WORK(&floppy_work, (work_func_t)empty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 del_timer(&fd_timer);
1022 spin_unlock_irqrestore(&floppy_lock, flags);
1023}
1024
1025/* this function makes sure that the disk stays in the drive during the
1026 * transfer */
1027static void fd_watchdog(void)
1028{
1029#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08001030 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 DPRINT("calling disk change from watchdog\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032#endif
1033
1034 if (disk_change(current_drive)) {
1035 DPRINT("disk removed during i/o\n");
1036 cancel_activity();
1037 cont->done(0);
1038 reset_fdc();
1039 } else {
1040 del_timer(&fd_timer);
1041 fd_timer.function = (timeout_fn) fd_watchdog;
1042 fd_timer.expires = jiffies + HZ / 10;
1043 add_timer(&fd_timer);
1044 }
1045}
1046
1047static void main_command_interrupt(void)
1048{
1049 del_timer(&fd_timer);
1050 cont->interrupt();
1051}
1052
1053/* waits for a delay (spinup or select) to pass */
1054static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
1055{
1056 if (FDCS->reset) {
1057 reset_fdc(); /* do the reset during sleep to win time
1058 * if we don't need to sleep, it's a good
1059 * occasion anyways */
1060 return 1;
1061 }
1062
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001063 if (time_before(jiffies, delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 del_timer(&fd_timer);
1065 fd_timer.function = function;
1066 fd_timer.expires = delay;
1067 add_timer(&fd_timer);
1068 return 1;
1069 }
1070 return 0;
1071}
1072
1073static DEFINE_SPINLOCK(floppy_hlt_lock);
1074static int hlt_disabled;
1075static void floppy_disable_hlt(void)
1076{
1077 unsigned long flags;
1078
1079 spin_lock_irqsave(&floppy_hlt_lock, flags);
1080 if (!hlt_disabled) {
1081 hlt_disabled = 1;
1082#ifdef HAVE_DISABLE_HLT
1083 disable_hlt();
1084#endif
1085 }
1086 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1087}
1088
1089static void floppy_enable_hlt(void)
1090{
1091 unsigned long flags;
1092
1093 spin_lock_irqsave(&floppy_hlt_lock, flags);
1094 if (hlt_disabled) {
1095 hlt_disabled = 0;
1096#ifdef HAVE_DISABLE_HLT
1097 enable_hlt();
1098#endif
1099 }
1100 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1101}
1102
1103static void setup_DMA(void)
1104{
1105 unsigned long f;
1106
1107#ifdef FLOPPY_SANITY_CHECK
1108 if (raw_cmd->length == 0) {
1109 int i;
1110
Joe Perchesb46df352010-03-10 15:20:46 -08001111 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001113 pr_cont("%x,", raw_cmd->cmd[i]);
1114 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 cont->done(0);
1116 FDCS->reset = 1;
1117 return;
1118 }
1119 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001120 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 cont->done(0);
1122 FDCS->reset = 1;
1123 return;
1124 }
1125#endif
1126 f = claim_dma_lock();
1127 fd_disable_dma();
1128#ifdef fd_dma_setup
1129 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1130 (raw_cmd->flags & FD_RAW_READ) ?
1131 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1132 release_dma_lock(f);
1133 cont->done(0);
1134 FDCS->reset = 1;
1135 return;
1136 }
1137 release_dma_lock(f);
1138#else
1139 fd_clear_dma_ff();
1140 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1141 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1142 DMA_MODE_READ : DMA_MODE_WRITE);
1143 fd_set_dma_addr(raw_cmd->kernel_data);
1144 fd_set_dma_count(raw_cmd->length);
1145 virtual_dma_port = FDCS->address;
1146 fd_enable_dma();
1147 release_dma_lock(f);
1148#endif
1149 floppy_disable_hlt();
1150}
1151
1152static void show_floppy(void);
1153
1154/* waits until the fdc becomes ready */
1155static int wait_til_ready(void)
1156{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001157 int status;
1158 int counter;
1159
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 if (FDCS->reset)
1161 return -1;
1162 for (counter = 0; counter < 10000; counter++) {
1163 status = fd_inb(FD_STATUS);
1164 if (status & STATUS_READY)
1165 return status;
1166 }
1167 if (!initialising) {
1168 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1169 show_floppy();
1170 }
1171 FDCS->reset = 1;
1172 return -1;
1173}
1174
1175/* sends a command byte to the fdc */
1176static int output_byte(char byte)
1177{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001178 int status = wait_til_ready();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001180 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 return -1;
1182 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY) {
1183 fd_outb(byte, FD_DATA);
1184#ifdef FLOPPY_SANITY_CHECK
1185 output_log[output_log_pos].data = byte;
1186 output_log[output_log_pos].status = status;
1187 output_log[output_log_pos].jiffies = jiffies;
1188 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
1189#endif
1190 return 0;
1191 }
1192 FDCS->reset = 1;
1193 if (!initialising) {
1194 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1195 byte, fdc, status);
1196 show_floppy();
1197 }
1198 return -1;
1199}
1200
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201/* gets the response from the fdc */
1202static int result(void)
1203{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001204 int i;
1205 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206
1207 for (i = 0; i < MAX_REPLIES; i++) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001208 status = wait_til_ready();
1209 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 break;
1211 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1212 if ((status & ~STATUS_BUSY) == STATUS_READY) {
1213#ifdef FLOPPY_SANITY_CHECK
1214 resultjiffies = jiffies;
1215 resultsize = i;
1216#endif
1217 return i;
1218 }
1219 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1220 reply_buffer[i] = fd_inb(FD_DATA);
1221 else
1222 break;
1223 }
1224 if (!initialising) {
1225 DPRINT
1226 ("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1227 fdc, status, i);
1228 show_floppy();
1229 }
1230 FDCS->reset = 1;
1231 return -1;
1232}
1233
1234#define MORE_OUTPUT -2
1235/* does the fdc need more output? */
1236static int need_more_output(void)
1237{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001238 int status = wait_til_ready();
Jesper Juhl06f748c2007-10-16 23:30:57 -07001239
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001240 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 return -1;
1242 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY)
1243 return MORE_OUTPUT;
1244 return result();
1245}
1246
1247/* Set perpendicular mode as required, based on data rate, if supported.
1248 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1249 */
1250static inline void perpendicular_mode(void)
1251{
1252 unsigned char perp_mode;
1253
1254 if (raw_cmd->rate & 0x40) {
1255 switch (raw_cmd->rate & 3) {
1256 case 0:
1257 perp_mode = 2;
1258 break;
1259 case 3:
1260 perp_mode = 3;
1261 break;
1262 default:
1263 DPRINT("Invalid data rate for perpendicular mode!\n");
1264 cont->done(0);
1265 FDCS->reset = 1; /* convenient way to return to
1266 * redo without to much hassle (deep
1267 * stack et al. */
1268 return;
1269 }
1270 } else
1271 perp_mode = 0;
1272
1273 if (FDCS->perp_mode == perp_mode)
1274 return;
1275 if (FDCS->version >= FDC_82077_ORIG) {
1276 output_byte(FD_PERPENDICULAR);
1277 output_byte(perp_mode);
1278 FDCS->perp_mode = perp_mode;
1279 } else if (perp_mode) {
1280 DPRINT("perpendicular mode not supported by this FDC.\n");
1281 }
1282} /* perpendicular_mode */
1283
1284static int fifo_depth = 0xa;
1285static int no_fifo;
1286
1287static int fdc_configure(void)
1288{
1289 /* Turn on FIFO */
1290 output_byte(FD_CONFIGURE);
1291 if (need_more_output() != MORE_OUTPUT)
1292 return 0;
1293 output_byte(0);
1294 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1295 output_byte(0); /* pre-compensation from track
1296 0 upwards */
1297 return 1;
1298}
1299
1300#define NOMINAL_DTR 500
1301
1302/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1303 * head load time, and DMA disable flag to values needed by floppy.
1304 *
1305 * The value "dtr" is the data transfer rate in Kbps. It is needed
1306 * to account for the data rate-based scaling done by the 82072 and 82077
1307 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1308 * 8272a).
1309 *
1310 * Note that changing the data transfer rate has a (probably deleterious)
1311 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1312 * fdc_specify is called again after each data transfer rate
1313 * change.
1314 *
1315 * srt: 1000 to 16000 in microseconds
1316 * hut: 16 to 240 milliseconds
1317 * hlt: 2 to 254 milliseconds
1318 *
1319 * These values are rounded up to the next highest available delay time.
1320 */
1321static void fdc_specify(void)
1322{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001323 unsigned char spec1;
1324 unsigned char spec2;
1325 unsigned long srt;
1326 unsigned long hlt;
1327 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 unsigned long dtr = NOMINAL_DTR;
1329 unsigned long scale_dtr = NOMINAL_DTR;
1330 int hlt_max_code = 0x7f;
1331 int hut_max_code = 0xf;
1332
1333 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1334 fdc_configure();
1335 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 }
1337
1338 switch (raw_cmd->rate & 0x03) {
1339 case 3:
1340 dtr = 1000;
1341 break;
1342 case 1:
1343 dtr = 300;
1344 if (FDCS->version >= FDC_82078) {
1345 /* chose the default rate table, not the one
1346 * where 1 = 2 Mbps */
1347 output_byte(FD_DRIVESPEC);
1348 if (need_more_output() == MORE_OUTPUT) {
1349 output_byte(UNIT(current_drive));
1350 output_byte(0xc0);
1351 }
1352 }
1353 break;
1354 case 2:
1355 dtr = 250;
1356 break;
1357 }
1358
1359 if (FDCS->version >= FDC_82072) {
1360 scale_dtr = dtr;
1361 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1362 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1363 }
1364
1365 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001366 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001367 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001369
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 SUPBOUND(srt, 0xf);
1371 INFBOUND(srt, 0);
1372
Julia Lawall061837b2008-09-22 14:57:16 -07001373 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 if (hlt < 0x01)
1375 hlt = 0x01;
1376 else if (hlt > 0x7f)
1377 hlt = hlt_max_code;
1378
Julia Lawall061837b2008-09-22 14:57:16 -07001379 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 if (hut < 0x1)
1381 hut = 0x1;
1382 else if (hut > 0xf)
1383 hut = hut_max_code;
1384
1385 spec1 = (srt << 4) | hut;
1386 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1387
1388 /* If these parameters did not change, just return with success */
1389 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1390 /* Go ahead and set spec1 and spec2 */
1391 output_byte(FD_SPECIFY);
1392 output_byte(FDCS->spec1 = spec1);
1393 output_byte(FDCS->spec2 = spec2);
1394 }
1395} /* fdc_specify */
1396
1397/* Set the FDC's data transfer rate on behalf of the specified drive.
1398 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1399 * of the specify command (i.e. using the fdc_specify function).
1400 */
1401static int fdc_dtr(void)
1402{
1403 /* If data rate not already set to desired value, set it. */
1404 if ((raw_cmd->rate & 3) == FDCS->dtr)
1405 return 0;
1406
1407 /* Set dtr */
1408 fd_outb(raw_cmd->rate & 3, FD_DCR);
1409
1410 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1411 * need a stabilization period of several milliseconds to be
1412 * enforced after data rate changes before R/W operations.
1413 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1414 */
1415 FDCS->dtr = raw_cmd->rate & 3;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001416 return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
1417 (timeout_fn)floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418} /* fdc_dtr */
1419
1420static void tell_sector(void)
1421{
Joe Perchesb46df352010-03-10 15:20:46 -08001422 pr_cont(": track %d, head %d, sector %d, size %d",
1423 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424} /* tell_sector */
1425
Joe Perchesb46df352010-03-10 15:20:46 -08001426static void print_errors(void)
1427{
1428 DPRINT("");
1429 if (ST0 & ST0_ECE) {
1430 pr_cont("Recalibrate failed!");
1431 } else if (ST2 & ST2_CRC) {
1432 pr_cont("data CRC error");
1433 tell_sector();
1434 } else if (ST1 & ST1_CRC) {
1435 pr_cont("CRC error");
1436 tell_sector();
1437 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1438 (ST2 & ST2_MAM)) {
1439 if (!probing) {
1440 pr_cont("sector not found");
1441 tell_sector();
1442 } else
1443 pr_cont("probe failed...");
1444 } else if (ST2 & ST2_WC) { /* seek error */
1445 pr_cont("wrong cylinder");
1446 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1447 pr_cont("bad cylinder");
1448 } else {
1449 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1450 ST0, ST1, ST2);
1451 tell_sector();
1452 }
1453 pr_cont("\n");
1454}
1455
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456/*
1457 * OK, this error interpreting routine is called after a
1458 * DMA read/write has succeeded
1459 * or failed, so we check the results, and copy any buffers.
1460 * hhb: Added better error reporting.
1461 * ak: Made this into a separate routine.
1462 */
1463static int interpret_errors(void)
1464{
1465 char bad;
1466
1467 if (inr != 7) {
1468 DPRINT("-- FDC reply error");
1469 FDCS->reset = 1;
1470 return 1;
1471 }
1472
1473 /* check IC to find cause of interrupt */
1474 switch (ST0 & ST0_INTR) {
1475 case 0x40: /* error occurred during command execution */
1476 if (ST1 & ST1_EOC)
1477 return 0; /* occurs with pseudo-DMA */
1478 bad = 1;
1479 if (ST1 & ST1_WP) {
1480 DPRINT("Drive is write protected\n");
1481 CLEARF(FD_DISK_WRITABLE);
1482 cont->done(0);
1483 bad = 2;
1484 } else if (ST1 & ST1_ND) {
1485 SETF(FD_NEED_TWADDLE);
1486 } else if (ST1 & ST1_OR) {
1487 if (DP->flags & FTD_MSG)
1488 DPRINT("Over/Underrun - retrying\n");
1489 bad = 0;
1490 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001491 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 }
1493 if (ST2 & ST2_WC || ST2 & ST2_BC)
1494 /* wrong cylinder => recal */
1495 DRS->track = NEED_2_RECAL;
1496 return bad;
1497 case 0x80: /* invalid command given */
1498 DPRINT("Invalid FDC command given!\n");
1499 cont->done(0);
1500 return 2;
1501 case 0xc0:
1502 DPRINT("Abnormal termination caused by polling\n");
1503 cont->error();
1504 return 2;
1505 default: /* (0) Normal command termination */
1506 return 0;
1507 }
1508}
1509
1510/*
1511 * This routine is called when everything should be correctly set up
1512 * for the transfer (i.e. floppy motor is on, the correct floppy is
1513 * selected, and the head is sitting on the right track).
1514 */
1515static void setup_rw_floppy(void)
1516{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001517 int i;
1518 int r;
1519 int flags;
1520 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 unsigned long ready_date;
1522 timeout_fn function;
1523
1524 flags = raw_cmd->flags;
1525 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1526 flags |= FD_RAW_INTR;
1527
1528 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1529 ready_date = DRS->spinup_date + DP->spinup;
1530 /* If spinup will take a long time, rerun scandrives
1531 * again just before spinup completion. Beware that
1532 * after scandrives, we must again wait for selection.
1533 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001534 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 ready_date -= DP->select_delay;
1536 function = (timeout_fn) floppy_start;
1537 } else
1538 function = (timeout_fn) setup_rw_floppy;
1539
1540 /* wait until the floppy is spinning fast enough */
1541 if (fd_wait_for_completion(ready_date, function))
1542 return;
1543 }
1544 dflags = DRS->flags;
1545
1546 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1547 setup_DMA();
1548
1549 if (flags & FD_RAW_INTR)
1550 do_floppy = main_command_interrupt;
1551
1552 r = 0;
1553 for (i = 0; i < raw_cmd->cmd_count; i++)
1554 r |= output_byte(raw_cmd->cmd[i]);
1555
1556 debugt("rw_command: ");
1557
1558 if (r) {
1559 cont->error();
1560 reset_fdc();
1561 return;
1562 }
1563
1564 if (!(flags & FD_RAW_INTR)) {
1565 inr = result();
1566 cont->interrupt();
1567 } else if (flags & FD_RAW_NEED_DISK)
1568 fd_watchdog();
1569}
1570
1571static int blind_seek;
1572
1573/*
1574 * This is the routine called after every seek (or recalibrate) interrupt
1575 * from the floppy controller.
1576 */
1577static void seek_interrupt(void)
1578{
1579 debugt("seek interrupt:");
1580 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1581 DPRINT("seek failed\n");
1582 DRS->track = NEED_2_RECAL;
1583 cont->error();
1584 cont->redo();
1585 return;
1586 }
1587 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
1588#ifdef DCL_DEBUG
1589 if (DP->flags & FD_DEBUG) {
Joe Perchesb46df352010-03-10 15:20:46 -08001590 DPRINT("clearing NEWCHANGE flag because of effective seek\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 DPRINT("jiffies=%lu\n", jiffies);
1592 }
1593#endif
1594 CLEARF(FD_DISK_NEWCHANGE); /* effective seek */
1595 DRS->select_date = jiffies;
1596 }
1597 DRS->track = ST1;
1598 floppy_ready();
1599}
1600
1601static void check_wp(void)
1602{
1603 if (TESTF(FD_VERIFY)) {
1604 /* check write protection */
1605 output_byte(FD_GETSTATUS);
1606 output_byte(UNIT(current_drive));
1607 if (result() != 1) {
1608 FDCS->reset = 1;
1609 return;
1610 }
1611 CLEARF(FD_VERIFY);
1612 CLEARF(FD_NEED_TWADDLE);
1613#ifdef DCL_DEBUG
1614 if (DP->flags & FD_DEBUG) {
1615 DPRINT("checking whether disk is write protected\n");
1616 DPRINT("wp=%x\n", ST3 & 0x40);
1617 }
1618#endif
1619 if (!(ST3 & 0x40))
1620 SETF(FD_DISK_WRITABLE);
1621 else
1622 CLEARF(FD_DISK_WRITABLE);
1623 }
1624}
1625
1626static void seek_floppy(void)
1627{
1628 int track;
1629
1630 blind_seek = 0;
1631
1632#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08001633 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 DPRINT("calling disk change from seek\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635#endif
1636
1637 if (!TESTF(FD_DISK_NEWCHANGE) &&
1638 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1639 /* the media changed flag should be cleared after the seek.
1640 * If it isn't, this means that there is really no disk in
1641 * the drive.
1642 */
1643 SETF(FD_DISK_CHANGED);
1644 cont->done(0);
1645 cont->redo();
1646 return;
1647 }
1648 if (DRS->track <= NEED_1_RECAL) {
1649 recalibrate_floppy();
1650 return;
1651 } else if (TESTF(FD_DISK_NEWCHANGE) &&
1652 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1653 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1654 /* we seek to clear the media-changed condition. Does anybody
1655 * know a more elegant way, which works on all drives? */
1656 if (raw_cmd->track)
1657 track = raw_cmd->track - 1;
1658 else {
1659 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1660 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1661 blind_seek = 1;
1662 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1663 }
1664 track = 1;
1665 }
1666 } else {
1667 check_wp();
1668 if (raw_cmd->track != DRS->track &&
1669 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1670 track = raw_cmd->track;
1671 else {
1672 setup_rw_floppy();
1673 return;
1674 }
1675 }
1676
1677 do_floppy = seek_interrupt;
1678 output_byte(FD_SEEK);
1679 output_byte(UNIT(current_drive));
Joe Perches2300f902010-03-10 15:20:49 -08001680 if (output_byte(track) < 0) {
1681 reset_fdc();
1682 return;
1683 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 debugt("seek command:");
1685}
1686
1687static void recal_interrupt(void)
1688{
1689 debugt("recal interrupt:");
1690 if (inr != 2)
1691 FDCS->reset = 1;
1692 else if (ST0 & ST0_ECE) {
1693 switch (DRS->track) {
1694 case NEED_1_RECAL:
1695 debugt("recal interrupt need 1 recal:");
1696 /* after a second recalibrate, we still haven't
1697 * reached track 0. Probably no drive. Raise an
1698 * error, as failing immediately might upset
1699 * computers possessed by the Devil :-) */
1700 cont->error();
1701 cont->redo();
1702 return;
1703 case NEED_2_RECAL:
1704 debugt("recal interrupt need 2 recal:");
1705 /* If we already did a recalibrate,
1706 * and we are not at track 0, this
1707 * means we have moved. (The only way
1708 * not to move at recalibration is to
1709 * be already at track 0.) Clear the
1710 * new change flag */
1711#ifdef DCL_DEBUG
Joe Perchesb46df352010-03-10 15:20:46 -08001712 if (DP->flags & FD_DEBUG)
1713 DPRINT("clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714#endif
1715
1716 CLEARF(FD_DISK_NEWCHANGE);
1717 DRS->select_date = jiffies;
1718 /* fall through */
1719 default:
1720 debugt("recal interrupt default:");
1721 /* Recalibrate moves the head by at
1722 * most 80 steps. If after one
1723 * recalibrate we don't have reached
1724 * track 0, this might mean that we
1725 * started beyond track 80. Try
1726 * again. */
1727 DRS->track = NEED_1_RECAL;
1728 break;
1729 }
1730 } else
1731 DRS->track = ST1;
1732 floppy_ready();
1733}
1734
1735static void print_result(char *message, int inr)
1736{
1737 int i;
1738
1739 DPRINT("%s ", message);
1740 if (inr >= 0)
1741 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001742 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1743 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744}
1745
1746/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001747irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 int do_print;
1750 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001751 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752
1753 lasthandler = handler;
1754 interruptjiffies = jiffies;
1755
1756 f = claim_dma_lock();
1757 fd_disable_dma();
1758 release_dma_lock(f);
1759
1760 floppy_enable_hlt();
1761 do_floppy = NULL;
1762 if (fdc >= N_FDC || FDCS->address == -1) {
1763 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001764 pr_info("DOR0=%x\n", fdc_state[0].dor);
1765 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
1766 pr_info("handler=%p\n", handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 is_alive("bizarre fdc");
1768 return IRQ_NONE;
1769 }
1770
1771 FDCS->reset = 0;
1772 /* We have to clear the reset flag here, because apparently on boxes
1773 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1774 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1775 * emission of the SENSEI's.
1776 * It is OK to emit floppy commands because we are in an interrupt
1777 * handler here, and thus we have to fear no interference of other
1778 * activity.
1779 */
1780
1781 do_print = !handler && print_unex && !initialising;
1782
1783 inr = result();
1784 if (do_print)
1785 print_result("unexpected interrupt", inr);
1786 if (inr == 0) {
1787 int max_sensei = 4;
1788 do {
1789 output_byte(FD_SENSEI);
1790 inr = result();
1791 if (do_print)
1792 print_result("sensei", inr);
1793 max_sensei--;
1794 } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2
1795 && max_sensei);
1796 }
1797 if (!handler) {
1798 FDCS->reset = 1;
1799 return IRQ_NONE;
1800 }
1801 schedule_bh(handler);
1802 is_alive("normal interrupt end");
1803
1804 /* FIXME! Was it really for us? */
1805 return IRQ_HANDLED;
1806}
1807
1808static void recalibrate_floppy(void)
1809{
1810 debugt("recalibrate floppy:");
1811 do_floppy = recal_interrupt;
1812 output_byte(FD_RECALIBRATE);
Joe Perches2300f902010-03-10 15:20:49 -08001813 if (output_byte(UNIT(current_drive)) < 0) {
1814 reset_fdc();
1815 return;
1816 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817}
1818
1819/*
1820 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1821 */
1822static void reset_interrupt(void)
1823{
1824 debugt("reset interrupt:");
1825 result(); /* get the status ready for set_fdc */
1826 if (FDCS->reset) {
Joe Perchesb46df352010-03-10 15:20:46 -08001827 pr_info("reset set in interrupt, calling %p\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 cont->error(); /* a reset just after a reset. BAD! */
1829 }
1830 cont->redo();
1831}
1832
1833/*
1834 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1835 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1836 */
1837static void reset_fdc(void)
1838{
1839 unsigned long flags;
1840
1841 do_floppy = reset_interrupt;
1842 FDCS->reset = 0;
1843 reset_fdc_info(0);
1844
1845 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1846 /* Irrelevant for systems with true DMA (i386). */
1847
1848 flags = claim_dma_lock();
1849 fd_disable_dma();
1850 release_dma_lock(flags);
1851
1852 if (FDCS->version >= FDC_82072A)
1853 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1854 else {
1855 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1856 udelay(FD_RESET_DELAY);
1857 fd_outb(FDCS->dor, FD_DOR);
1858 }
1859}
1860
1861static void show_floppy(void)
1862{
1863 int i;
1864
Joe Perchesb46df352010-03-10 15:20:46 -08001865 pr_info("\n");
1866 pr_info("floppy driver state\n");
1867 pr_info("-------------------\n");
1868 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%p\n",
1869 jiffies, interruptjiffies, jiffies - interruptjiffies,
1870 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871
1872#ifdef FLOPPY_SANITY_CHECK
Joe Perchesb46df352010-03-10 15:20:46 -08001873 pr_info("timeout_message=%s\n", timeout_message);
1874 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001876 pr_info("%2x %2x %lu\n",
1877 output_log[(i + output_log_pos) % OLOGSIZE].data,
1878 output_log[(i + output_log_pos) % OLOGSIZE].status,
1879 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1880 pr_info("last result at %lu\n", resultjiffies);
1881 pr_info("last redo_fd_request at %lu\n", lastredo);
1882 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1883 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884#endif
1885
Joe Perchesb46df352010-03-10 15:20:46 -08001886 pr_info("status=%x\n", fd_inb(FD_STATUS));
1887 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 if (do_floppy)
Joe Perchesb46df352010-03-10 15:20:46 -08001889 pr_info("do_floppy=%p\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001890 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08001891 pr_info("floppy_work.func=%p\n", floppy_work.func);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08001893 pr_info("fd_timer.function=%p\n", fd_timer.function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 if (timer_pending(&fd_timeout)) {
Joe Perchesb46df352010-03-10 15:20:46 -08001895 pr_info("timer_function=%p\n", fd_timeout.function);
1896 pr_info("expires=%lu\n", fd_timeout.expires - jiffies);
1897 pr_info("now=%lu\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 }
Joe Perchesb46df352010-03-10 15:20:46 -08001899 pr_info("cont=%p\n", cont);
1900 pr_info("current_req=%p\n", current_req);
1901 pr_info("command_status=%d\n", command_status);
1902 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903}
1904
1905static void floppy_shutdown(unsigned long data)
1906{
1907 unsigned long flags;
1908
1909 if (!initialising)
1910 show_floppy();
1911 cancel_activity();
1912
1913 floppy_enable_hlt();
1914
1915 flags = claim_dma_lock();
1916 fd_disable_dma();
1917 release_dma_lock(flags);
1918
1919 /* avoid dma going to a random drive after shutdown */
1920
1921 if (!initialising)
1922 DPRINT("floppy timeout called\n");
1923 FDCS->reset = 1;
1924 if (cont) {
1925 cont->done(0);
1926 cont->redo(); /* this will recall reset when needed */
1927 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001928 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 process_fd_request();
1930 }
1931 is_alive("floppy shutdown");
1932}
1933
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001935static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001937 int mask;
1938 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939
1940 mask = 0xfc;
1941 data = UNIT(current_drive);
1942 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1943 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1944 set_debugt();
1945 /* no read since this drive is running */
1946 DRS->first_read_date = 0;
1947 /* note motor start time if motor is not yet running */
1948 DRS->spinup_date = jiffies;
1949 data |= (0x10 << UNIT(current_drive));
1950 }
1951 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1952 mask &= ~(0x10 << UNIT(current_drive));
1953
1954 /* starts motor and selects floppy */
1955 del_timer(motor_off_timer + current_drive);
1956 set_dor(fdc, mask, data);
1957
1958 /* wait_for_completion also schedules reset if needed. */
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001959 return fd_wait_for_completion(DRS->select_date + DP->select_delay,
1960 (timeout_fn)function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961}
1962
1963static void floppy_ready(void)
1964{
Joe Perches045f9832010-03-10 15:20:47 -08001965 if (FDCS->reset) {
1966 reset_fdc();
1967 return;
1968 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 if (start_motor(floppy_ready))
1970 return;
1971 if (fdc_dtr())
1972 return;
1973
1974#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08001975 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 DPRINT("calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977#endif
1978 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1979 disk_change(current_drive) && !DP->select_delay)
1980 twaddle(); /* this clears the dcl on certain drive/controller
1981 * combinations */
1982
1983#ifdef fd_chose_dma_mode
1984 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1985 unsigned long flags = claim_dma_lock();
1986 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1987 release_dma_lock(flags);
1988 }
1989#endif
1990
1991 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1992 perpendicular_mode();
1993 fdc_specify(); /* must be done here because of hut, hlt ... */
1994 seek_floppy();
1995 } else {
1996 if ((raw_cmd->flags & FD_RAW_READ) ||
1997 (raw_cmd->flags & FD_RAW_WRITE))
1998 fdc_specify();
1999 setup_rw_floppy();
2000 }
2001}
2002
2003static void floppy_start(void)
2004{
2005 reschedule_timeout(current_reqD, "floppy start", 0);
2006
2007 scandrives();
2008#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08002009 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 DPRINT("setting NEWCHANGE in floppy_start\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011#endif
2012 SETF(FD_DISK_NEWCHANGE);
2013 floppy_ready();
2014}
2015
2016/*
2017 * ========================================================================
2018 * here ends the bottom half. Exported routines are:
2019 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
2020 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
2021 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
2022 * and set_dor.
2023 * ========================================================================
2024 */
2025/*
2026 * General purpose continuations.
2027 * ==============================
2028 */
2029
2030static void do_wakeup(void)
2031{
2032 reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);
2033 cont = NULL;
2034 command_status += 2;
2035 wake_up(&command_done);
2036}
2037
2038static struct cont_t wakeup_cont = {
2039 .interrupt = empty,
2040 .redo = do_wakeup,
2041 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002042 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043};
2044
2045static struct cont_t intr_cont = {
2046 .interrupt = empty,
2047 .redo = process_fd_request,
2048 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002049 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050};
2051
Jesper Juhl06f748c2007-10-16 23:30:57 -07002052static int wait_til_done(void (*handler)(void), int interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053{
2054 int ret;
2055
2056 schedule_bh(handler);
2057
2058 if (command_status < 2 && NO_SIGNAL) {
2059 DECLARE_WAITQUEUE(wait, current);
2060
2061 add_wait_queue(&command_done, &wait);
2062 for (;;) {
2063 set_current_state(interruptible ?
2064 TASK_INTERRUPTIBLE :
2065 TASK_UNINTERRUPTIBLE);
2066
2067 if (command_status >= 2 || !NO_SIGNAL)
2068 break;
2069
2070 is_alive("wait_til_done");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 schedule();
2072 }
2073
2074 set_current_state(TASK_RUNNING);
2075 remove_wait_queue(&command_done, &wait);
2076 }
2077
2078 if (command_status < 2) {
2079 cancel_activity();
2080 cont = &intr_cont;
2081 reset_fdc();
2082 return -EINTR;
2083 }
2084
2085 if (FDCS->reset)
2086 command_status = FD_COMMAND_ERROR;
2087 if (command_status == FD_COMMAND_OKAY)
2088 ret = 0;
2089 else
2090 ret = -EIO;
2091 command_status = FD_COMMAND_NONE;
2092 return ret;
2093}
2094
2095static void generic_done(int result)
2096{
2097 command_status = result;
2098 cont = &wakeup_cont;
2099}
2100
2101static void generic_success(void)
2102{
2103 cont->done(1);
2104}
2105
2106static void generic_failure(void)
2107{
2108 cont->done(0);
2109}
2110
2111static void success_and_wakeup(void)
2112{
2113 generic_success();
2114 cont->redo();
2115}
2116
2117/*
2118 * formatting and rw support.
2119 * ==========================
2120 */
2121
2122static int next_valid_format(void)
2123{
2124 int probed_format;
2125
2126 probed_format = DRS->probed_format;
2127 while (1) {
2128 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2129 DRS->probed_format = 0;
2130 return 1;
2131 }
2132 if (floppy_type[DP->autodetect[probed_format]].sect) {
2133 DRS->probed_format = probed_format;
2134 return 0;
2135 }
2136 probed_format++;
2137 }
2138}
2139
2140static void bad_flp_intr(void)
2141{
2142 int err_count;
2143
2144 if (probing) {
2145 DRS->probed_format++;
2146 if (!next_valid_format())
2147 return;
2148 }
2149 err_count = ++(*errors);
2150 INFBOUND(DRWE->badness, err_count);
2151 if (err_count > DP->max_errors.abort)
2152 cont->done(0);
2153 if (err_count > DP->max_errors.reset)
2154 FDCS->reset = 1;
2155 else if (err_count > DP->max_errors.recal)
2156 DRS->track = NEED_2_RECAL;
2157}
2158
2159static void set_floppy(int drive)
2160{
2161 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002162
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 if (type)
2164 _floppy = floppy_type + type;
2165 else
2166 _floppy = current_type[drive];
2167}
2168
2169/*
2170 * formatting support.
2171 * ===================
2172 */
2173static void format_interrupt(void)
2174{
2175 switch (interpret_errors()) {
2176 case 1:
2177 cont->error();
2178 case 2:
2179 break;
2180 case 0:
2181 cont->done(1);
2182 }
2183 cont->redo();
2184}
2185
2186#define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2)
Joe Perches48c8cee2010-03-10 15:20:45 -08002187#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002189
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190static void setup_format_params(int track)
2191{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002192 int n;
2193 int il;
2194 int count;
2195 int head_shift;
2196 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 struct fparm {
2198 unsigned char track, head, sect, size;
2199 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200
2201 raw_cmd = &default_raw_cmd;
2202 raw_cmd->track = track;
2203
Joe Perches48c8cee2010-03-10 15:20:45 -08002204 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2205 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 raw_cmd->rate = _floppy->rate & 0x43;
2207 raw_cmd->cmd_count = NR_F;
2208 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2209 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2210 F_SIZECODE = FD_SIZECODE(_floppy);
2211 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2212 F_GAP = _floppy->fmt_gap;
2213 F_FILL = FD_FILL_BYTE;
2214
2215 raw_cmd->kernel_data = floppy_track_buffer;
2216 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2217
2218 /* allow for about 30ms for data transport per track */
2219 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2220
2221 /* a ``cylinder'' is two tracks plus a little stepping time */
2222 track_shift = 2 * head_shift + 3;
2223
2224 /* position of logical sector 1 on this track */
2225 n = (track_shift * format_req.track + head_shift * format_req.head)
2226 % F_SECT_PER_TRACK;
2227
2228 /* determine interleave */
2229 il = 1;
2230 if (_floppy->fmt_gap < 0x22)
2231 il++;
2232
2233 /* initialize field */
2234 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2235 here[count].track = format_req.track;
2236 here[count].head = format_req.head;
2237 here[count].sect = 0;
2238 here[count].size = F_SIZECODE;
2239 }
2240 /* place logical sectors */
2241 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2242 here[n].sect = count;
2243 n = (n + il) % F_SECT_PER_TRACK;
2244 if (here[n].sect) { /* sector busy, find next free sector */
2245 ++n;
2246 if (n >= F_SECT_PER_TRACK) {
2247 n -= F_SECT_PER_TRACK;
2248 while (here[n].sect)
2249 ++n;
2250 }
2251 }
2252 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002253 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002255 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 }
2257}
2258
2259static void redo_format(void)
2260{
2261 buffer_track = -1;
2262 setup_format_params(format_req.track << STRETCH(_floppy));
2263 floppy_start();
2264 debugt("queue format request");
2265}
2266
2267static struct cont_t format_cont = {
2268 .interrupt = format_interrupt,
2269 .redo = redo_format,
2270 .error = bad_flp_intr,
2271 .done = generic_done
2272};
2273
2274static int do_format(int drive, struct format_descr *tmp_format_req)
2275{
2276 int ret;
2277
2278 LOCK_FDC(drive, 1);
2279 set_floppy(drive);
2280 if (!_floppy ||
2281 _floppy->track > DP->tracks ||
2282 tmp_format_req->track >= _floppy->track ||
2283 tmp_format_req->head >= _floppy->head ||
2284 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2285 !_floppy->fmt_gap) {
2286 process_fd_request();
2287 return -EINVAL;
2288 }
2289 format_req = *tmp_format_req;
2290 format_errors = 0;
2291 cont = &format_cont;
2292 errors = &format_errors;
2293 IWAIT(redo_format);
2294 process_fd_request();
2295 return ret;
2296}
2297
2298/*
2299 * Buffer read/write and support
2300 * =============================
2301 */
2302
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002303static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304{
2305 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002306 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307
2308 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002309 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002310 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002311 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313
2314 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002315 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 current_req = NULL;
2317}
2318
2319/* new request_done. Can handle physical sectors which are smaller than a
2320 * logical buffer */
2321static void request_done(int uptodate)
2322{
2323 struct request_queue *q = floppy_queue;
2324 struct request *req = current_req;
2325 unsigned long flags;
2326 int block;
2327
2328 probing = 0;
Joe Perchesb46df352010-03-10 15:20:46 -08002329 reschedule_timeout(MAXTIMEOUT, "request done", uptodate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330
2331 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002332 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 return;
2334 }
2335
2336 if (uptodate) {
2337 /* maintain values for invalidation on geometry
2338 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002339 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 INFBOUND(DRS->maxblock, block);
2341 if (block > _floppy->sect)
2342 DRS->maxtrack = 1;
2343
2344 /* unlock chained buffers */
2345 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002346 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347 spin_unlock_irqrestore(q->queue_lock, flags);
2348 } else {
2349 if (rq_data_dir(req) == WRITE) {
2350 /* record write error information */
2351 DRWE->write_errors++;
2352 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002353 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 DRWE->first_error_generation = DRS->generation;
2355 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002356 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 DRWE->last_error_generation = DRS->generation;
2358 }
2359 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002360 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 spin_unlock_irqrestore(q->queue_lock, flags);
2362 }
2363}
2364
2365/* Interrupt handler evaluating the result of the r/w operation */
2366static void rw_interrupt(void)
2367{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002368 int eoc;
2369 int ssize;
2370 int heads;
2371 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372
2373 if (R_HEAD >= 2) {
2374 /* some Toshiba floppy controllers occasionnally seem to
2375 * return bogus interrupts after read/write operations, which
2376 * can be recognized by a bad head number (>= 2) */
2377 return;
2378 }
2379
2380 if (!DRS->first_read_date)
2381 DRS->first_read_date = jiffies;
2382
2383 nr_sectors = 0;
2384 CODE2SIZE;
2385
2386 if (ST1 & ST1_EOC)
2387 eoc = 1;
2388 else
2389 eoc = 0;
2390
2391 if (COMMAND & 0x80)
2392 heads = 2;
2393 else
2394 heads = 1;
2395
2396 nr_sectors = (((R_TRACK - TRACK) * heads +
2397 R_HEAD - HEAD) * SECT_PER_TRACK +
2398 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2399
2400#ifdef FLOPPY_SANITY_CHECK
2401 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002402 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 DPRINT("long rw: %x instead of %lx\n",
2404 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002405 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2406 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2407 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2408 pr_info("heads=%d eoc=%d\n", heads, eoc);
2409 pr_info("spt=%d st=%d ss=%d\n",
2410 SECT_PER_TRACK, fsector_t, ssize);
2411 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 }
2413#endif
2414
2415 nr_sectors -= in_sector_offset;
2416 INFBOUND(nr_sectors, 0);
2417 SUPBOUND(current_count_sectors, nr_sectors);
2418
2419 switch (interpret_errors()) {
2420 case 2:
2421 cont->redo();
2422 return;
2423 case 1:
2424 if (!current_count_sectors) {
2425 cont->error();
2426 cont->redo();
2427 return;
2428 }
2429 break;
2430 case 0:
2431 if (!current_count_sectors) {
2432 cont->redo();
2433 return;
2434 }
2435 current_type[current_drive] = _floppy;
2436 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2437 break;
2438 }
2439
2440 if (probing) {
2441 if (DP->flags & FTD_MSG)
2442 DPRINT("Auto-detected floppy type %s in fd%d\n",
2443 _floppy->name, current_drive);
2444 current_type[current_drive] = _floppy;
2445 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2446 probing = 0;
2447 }
2448
2449 if (CT(COMMAND) != FD_READ ||
2450 raw_cmd->kernel_data == current_req->buffer) {
2451 /* transfer directly from buffer */
2452 cont->done(1);
2453 } else if (CT(COMMAND) == FD_READ) {
2454 buffer_track = raw_cmd->track;
2455 buffer_drive = current_drive;
2456 INFBOUND(buffer_max, nr_sectors + fsector_t);
2457 }
2458 cont->redo();
2459}
2460
2461/* Compute maximal contiguous buffer size. */
2462static int buffer_chain_size(void)
2463{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 struct bio_vec *bv;
NeilBrown5705f702007-09-25 12:35:59 +02002465 int size;
2466 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 char *base;
2468
2469 base = bio_data(current_req->bio);
2470 size = 0;
2471
NeilBrown5705f702007-09-25 12:35:59 +02002472 rq_for_each_segment(bv, current_req, iter) {
2473 if (page_address(bv->bv_page) + bv->bv_offset != base + size)
2474 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475
NeilBrown5705f702007-09-25 12:35:59 +02002476 size += bv->bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 }
2478
2479 return size >> 9;
2480}
2481
2482/* Compute the maximal transfer size */
2483static int transfer_size(int ssize, int max_sector, int max_size)
2484{
2485 SUPBOUND(max_sector, fsector_t + max_size);
2486
2487 /* alignment */
2488 max_sector -= (max_sector % _floppy->sect) % ssize;
2489
2490 /* transfer size, beginning not aligned */
2491 current_count_sectors = max_sector - fsector_t;
2492
2493 return max_sector;
2494}
2495
2496/*
2497 * Move data from/to the track buffer to/from the buffer cache.
2498 */
2499static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2500{
2501 int remaining; /* number of transferred 512-byte sectors */
2502 struct bio_vec *bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002503 char *buffer;
2504 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002505 int size;
2506 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507
2508 max_sector = transfer_size(ssize,
2509 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002510 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511
2512 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002513 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002515 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516
2517 remaining = current_count_sectors << 9;
2518#ifdef FLOPPY_SANITY_CHECK
Tejun Heo1011c1b2009-05-07 22:24:45 +09002519 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002521 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2522 pr_info("remaining=%d\n", remaining >> 9);
2523 pr_info("current_req->nr_sectors=%u\n",
2524 blk_rq_sectors(current_req));
2525 pr_info("current_req->current_nr_sectors=%u\n",
2526 blk_rq_cur_sectors(current_req));
2527 pr_info("max_sector=%d\n", max_sector);
2528 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 }
2530#endif
2531
2532 buffer_max = max(max_sector, buffer_max);
2533
2534 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2535
Tejun Heo1011c1b2009-05-07 22:24:45 +09002536 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537
NeilBrown5705f702007-09-25 12:35:59 +02002538 rq_for_each_segment(bv, current_req, iter) {
2539 if (!remaining)
2540 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541
NeilBrown5705f702007-09-25 12:35:59 +02002542 size = bv->bv_len;
2543 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544
NeilBrown5705f702007-09-25 12:35:59 +02002545 buffer = page_address(bv->bv_page) + bv->bv_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546#ifdef FLOPPY_SANITY_CHECK
NeilBrown5705f702007-09-25 12:35:59 +02002547 if (dma_buffer + size >
2548 floppy_track_buffer + (max_buffer_sectors << 10) ||
2549 dma_buffer < floppy_track_buffer) {
2550 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002551 (int)((floppy_track_buffer - dma_buffer) >> 9));
2552 pr_info("fsector_t=%d buffer_min=%d\n",
2553 fsector_t, buffer_min);
2554 pr_info("current_count_sectors=%ld\n",
2555 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002557 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002558 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002559 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002560 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 }
NeilBrown5705f702007-09-25 12:35:59 +02002562 if (((unsigned long)buffer) % 512)
2563 DPRINT("%p buffer not aligned\n", buffer);
2564#endif
2565 if (CT(COMMAND) == FD_READ)
2566 memcpy(buffer, dma_buffer, size);
2567 else
2568 memcpy(dma_buffer, buffer, size);
2569
2570 remaining -= size;
2571 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 }
2573#ifdef FLOPPY_SANITY_CHECK
2574 if (remaining) {
2575 if (remaining > 0)
2576 max_sector -= remaining >> 9;
2577 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2578 }
2579#endif
2580}
2581
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582/* work around a bug in pseudo DMA
2583 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2584 * sending data. Hence we need a different way to signal the
2585 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2586 * does not work with MT, hence we can only transfer one head at
2587 * a time
2588 */
2589static void virtualdmabug_workaround(void)
2590{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002591 int hard_sectors;
2592 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593
2594 if (CT(COMMAND) == FD_WRITE) {
2595 COMMAND &= ~0x80; /* switch off multiple track mode */
2596
2597 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2598 end_sector = SECTOR + hard_sectors - 1;
2599#ifdef FLOPPY_SANITY_CHECK
2600 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002601 pr_info("too many sectors %d > %d\n",
2602 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 return;
2604 }
2605#endif
Joe Perches48c8cee2010-03-10 15:20:45 -08002606 SECT_PER_TRACK = end_sector;
2607 /* make sure SECT_PER_TRACK
2608 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 }
2610}
2611
2612/*
2613 * Formulate a read/write request.
2614 * this routine decides where to load the data (directly to buffer, or to
2615 * tmp floppy area), how much data to load (the size of the buffer, the whole
2616 * track, or a single sector)
2617 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2618 * allocation on the fly, it should be done here. No other part should need
2619 * modification.
2620 */
2621
2622static int make_raw_rw_request(void)
2623{
2624 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002625 int max_sector;
2626 int max_size;
2627 int tracksize;
2628 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629
2630 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002631 pr_info("VFS: Block I/O scheduled on unopened device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 return 0;
2633 }
2634
2635 set_fdc((long)current_req->rq_disk->private_data);
2636
2637 raw_cmd = &default_raw_cmd;
2638 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
2639 FD_RAW_NEED_SEEK;
2640 raw_cmd->cmd_count = NR_RW;
2641 if (rq_data_dir(current_req) == READ) {
2642 raw_cmd->flags |= FD_RAW_READ;
2643 COMMAND = FM_MODE(_floppy, FD_READ);
2644 } else if (rq_data_dir(current_req) == WRITE) {
2645 raw_cmd->flags |= FD_RAW_WRITE;
2646 COMMAND = FM_MODE(_floppy, FD_WRITE);
2647 } else {
2648 DPRINT("make_raw_rw_request: unknown command\n");
2649 return 0;
2650 }
2651
2652 max_sector = _floppy->sect * _floppy->head;
2653
Tejun Heo83096eb2009-05-07 22:24:39 +09002654 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2655 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002657 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 current_count_sectors = 1;
2659 return 1;
2660 } else
2661 return 0;
2662 }
2663 HEAD = fsector_t / _floppy->sect;
2664
Keith Wansbrough9e491842008-09-22 14:57:17 -07002665 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 TESTF(FD_NEED_TWADDLE)) && fsector_t < _floppy->sect)
2667 max_sector = _floppy->sect;
2668
2669 /* 2M disks have phantom sectors on the first track */
2670 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2671 max_sector = 2 * _floppy->sect / 3;
2672 if (fsector_t >= max_sector) {
2673 current_count_sectors =
2674 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002675 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 return 1;
2677 }
2678 SIZECODE = 2;
2679 } else
2680 SIZECODE = FD_SIZECODE(_floppy);
2681 raw_cmd->rate = _floppy->rate & 0x43;
2682 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2683 raw_cmd->rate = 1;
2684
2685 if (SIZECODE)
2686 SIZECODE2 = 0xff;
2687 else
2688 SIZECODE2 = 0x80;
2689 raw_cmd->track = TRACK << STRETCH(_floppy);
2690 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2691 GAP = _floppy->gap;
2692 CODE2SIZE;
2693 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2694 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002695 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696
2697 /* tracksize describes the size which can be filled up with sectors
2698 * of size ssize.
2699 */
2700 tracksize = _floppy->sect - _floppy->sect % ssize;
2701 if (tracksize < _floppy->sect) {
2702 SECT_PER_TRACK++;
2703 if (tracksize <= fsector_t % _floppy->sect)
2704 SECTOR--;
2705
2706 /* if we are beyond tracksize, fill up using smaller sectors */
2707 while (tracksize <= fsector_t % _floppy->sect) {
2708 while (tracksize + ssize > _floppy->sect) {
2709 SIZECODE--;
2710 ssize >>= 1;
2711 }
2712 SECTOR++;
2713 SECT_PER_TRACK++;
2714 tracksize += ssize;
2715 }
2716 max_sector = HEAD * _floppy->sect + tracksize;
2717 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2718 max_sector = _floppy->sect;
2719 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2720 /* for virtual DMA bug workaround */
2721 max_sector = _floppy->sect;
2722 }
2723
2724 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2725 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002726 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 if ((raw_cmd->track == buffer_track) &&
2728 (current_drive == buffer_drive) &&
2729 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2730 /* data already in track buffer */
2731 if (CT(COMMAND) == FD_READ) {
2732 copy_buffer(1, max_sector, buffer_max);
2733 return 1;
2734 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002735 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 if (CT(COMMAND) == FD_WRITE) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002737 unsigned int sectors;
2738
2739 sectors = fsector_t + blk_rq_sectors(current_req);
2740 if (sectors > ssize && sectors < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 max_size = ssize + ssize;
2742 else
2743 max_size = ssize;
2744 }
2745 raw_cmd->flags &= ~FD_RAW_WRITE;
2746 raw_cmd->flags |= FD_RAW_READ;
2747 COMMAND = FM_MODE(_floppy, FD_READ);
2748 } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) {
2749 unsigned long dma_limit;
2750 int direct, indirect;
2751
2752 indirect =
2753 transfer_size(ssize, max_sector,
2754 max_buffer_sectors * 2) - fsector_t;
2755
2756 /*
2757 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2758 * on a 64 bit machine!
2759 */
2760 max_size = buffer_chain_size();
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002761 dma_limit = (MAX_DMA_ADDRESS -
2762 ((unsigned long)current_req->buffer)) >> 9;
Joe Perchesa81ee542010-03-10 15:20:46 -08002763 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 /* 64 kb boundaries */
2766 if (CROSS_64KB(current_req->buffer, max_size << 9))
2767 max_size = (K_64 -
2768 ((unsigned long)current_req->buffer) %
2769 K_64) >> 9;
2770 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2771 /*
2772 * We try to read tracks, but if we get too many errors, we
2773 * go back to reading just one sector at a time.
2774 *
2775 * This means we should be able to read a sector even if there
2776 * are other bad sectors on this track.
2777 */
2778 if (!direct ||
2779 (indirect * 2 > direct * 3 &&
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002780 *errors < DP->max_errors.read_track &&
2781 ((!probing ||
2782 (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002783 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 } else {
2785 raw_cmd->kernel_data = current_req->buffer;
2786 raw_cmd->length = current_count_sectors << 9;
2787 if (raw_cmd->length == 0) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002788 DPRINT("zero dma transfer attempted from make_raw_request\n");
2789 DPRINT("indirect=%d direct=%d fsector_t=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 indirect, direct, fsector_t);
2791 return 0;
2792 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 virtualdmabug_workaround();
2794 return 2;
2795 }
2796 }
2797
2798 if (CT(COMMAND) == FD_READ)
2799 max_size = max_sector; /* unbounded */
2800
2801 /* claim buffer track if needed */
2802 if (buffer_track != raw_cmd->track || /* bad track */
2803 buffer_drive != current_drive || /* bad drive */
2804 fsector_t > buffer_max ||
2805 fsector_t < buffer_min ||
2806 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002807 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 max_sector > 2 * max_buffer_sectors + buffer_min &&
2809 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)
2810 /* not enough space */
2811 ) {
2812 buffer_track = -1;
2813 buffer_drive = current_drive;
2814 buffer_max = buffer_min = aligned_sector_t;
2815 }
2816 raw_cmd->kernel_data = floppy_track_buffer +
2817 ((aligned_sector_t - buffer_min) << 9);
2818
2819 if (CT(COMMAND) == FD_WRITE) {
2820 /* copy write buffer to track buffer.
2821 * if we get here, we know that the write
2822 * is either aligned or the data already in the buffer
2823 * (buffer will be overwritten) */
2824#ifdef FLOPPY_SANITY_CHECK
2825 if (in_sector_offset && buffer_track == -1)
2826 DPRINT("internal error offset !=0 on write\n");
2827#endif
2828 buffer_track = raw_cmd->track;
2829 buffer_drive = current_drive;
2830 copy_buffer(ssize, max_sector,
2831 2 * max_buffer_sectors + buffer_min);
2832 } else
2833 transfer_size(ssize, max_sector,
2834 2 * max_buffer_sectors + buffer_min -
2835 aligned_sector_t);
2836
2837 /* round up current_count_sectors to get dma xfer size */
2838 raw_cmd->length = in_sector_offset + current_count_sectors;
2839 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2840 raw_cmd->length <<= 9;
2841#ifdef FLOPPY_SANITY_CHECK
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 if ((raw_cmd->length < current_count_sectors << 9) ||
2843 (raw_cmd->kernel_data != current_req->buffer &&
2844 CT(COMMAND) == FD_WRITE &&
2845 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2846 aligned_sector_t < buffer_min)) ||
2847 raw_cmd->length % (128 << SIZECODE) ||
2848 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2849 DPRINT("fractionary current count b=%lx s=%lx\n",
2850 raw_cmd->length, current_count_sectors);
2851 if (raw_cmd->kernel_data != current_req->buffer)
Joe Perchesb46df352010-03-10 15:20:46 -08002852 pr_info("addr=%d, length=%ld\n",
2853 (int)((raw_cmd->kernel_data -
2854 floppy_track_buffer) >> 9),
2855 current_count_sectors);
2856 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2857 fsector_t, aligned_sector_t, max_sector, max_size);
2858 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2859 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2860 COMMAND, SECTOR, HEAD, TRACK);
2861 pr_info("buffer drive=%d\n", buffer_drive);
2862 pr_info("buffer track=%d\n", buffer_track);
2863 pr_info("buffer_min=%d\n", buffer_min);
2864 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 return 0;
2866 }
2867
2868 if (raw_cmd->kernel_data != current_req->buffer) {
2869 if (raw_cmd->kernel_data < floppy_track_buffer ||
2870 current_count_sectors < 0 ||
2871 raw_cmd->length < 0 ||
2872 raw_cmd->kernel_data + raw_cmd->length >
2873 floppy_track_buffer + (max_buffer_sectors << 10)) {
2874 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002875 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2876 fsector_t, buffer_min, raw_cmd->length >> 9);
2877 pr_info("current_count_sectors=%ld\n",
2878 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002880 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002882 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 return 0;
2884 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002885 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002886 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 DPRINT("buffer overrun in direct transfer\n");
2888 return 0;
2889 } else if (raw_cmd->length < current_count_sectors << 9) {
2890 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002891 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2892 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 }
2894 if (raw_cmd->length == 0) {
2895 DPRINT("zero dma transfer attempted from make_raw_request\n");
2896 return 0;
2897 }
2898#endif
2899
2900 virtualdmabug_workaround();
2901 return 2;
2902}
2903
2904static void redo_fd_request(void)
2905{
2906#define REPEAT {request_done(0); continue; }
2907 int drive;
2908 int tmp;
2909
2910 lastredo = jiffies;
2911 if (current_drive < N_DRIVE)
2912 floppy_off(current_drive);
2913
2914 for (;;) {
2915 if (!current_req) {
2916 struct request *req;
2917
2918 spin_lock_irq(floppy_queue->queue_lock);
Tejun Heo9934c8c2009-05-08 11:54:16 +09002919 req = blk_fetch_request(floppy_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 spin_unlock_irq(floppy_queue->queue_lock);
2921 if (!req) {
2922 do_floppy = NULL;
2923 unlock_fdc();
2924 return;
2925 }
2926 current_req = req;
2927 }
2928 drive = (long)current_req->rq_disk->private_data;
2929 set_fdc(drive);
2930 reschedule_timeout(current_reqD, "redo fd request", 0);
2931
2932 set_floppy(drive);
2933 raw_cmd = &default_raw_cmd;
2934 raw_cmd->flags = 0;
2935 if (start_motor(redo_fd_request))
2936 return;
2937 disk_change(current_drive);
2938 if (test_bit(current_drive, &fake_change) ||
2939 TESTF(FD_DISK_CHANGED)) {
2940 DPRINT("disk absent or changed during operation\n");
2941 REPEAT;
2942 }
2943 if (!_floppy) { /* Autodetection */
2944 if (!probing) {
2945 DRS->probed_format = 0;
2946 if (next_valid_format()) {
2947 DPRINT("no autodetectable formats\n");
2948 _floppy = NULL;
2949 REPEAT;
2950 }
2951 }
2952 probing = 1;
2953 _floppy =
2954 floppy_type + DP->autodetect[DRS->probed_format];
2955 } else
2956 probing = 0;
2957 errors = &(current_req->errors);
2958 tmp = make_raw_rw_request();
2959 if (tmp < 2) {
2960 request_done(tmp);
2961 continue;
2962 }
2963
2964 if (TESTF(FD_NEED_TWADDLE))
2965 twaddle();
2966 schedule_bh(floppy_start);
2967 debugt("queue fd request");
2968 return;
2969 }
2970#undef REPEAT
2971}
2972
2973static struct cont_t rw_cont = {
2974 .interrupt = rw_interrupt,
2975 .redo = redo_fd_request,
2976 .error = bad_flp_intr,
2977 .done = request_done
2978};
2979
2980static void process_fd_request(void)
2981{
2982 cont = &rw_cont;
2983 schedule_bh(redo_fd_request);
2984}
2985
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002986static void do_fd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987{
2988 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002989 pr_info("VFS: do_fd_request called on non-open device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 return;
2991 }
2992
2993 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002994 pr_info("warning: usage count=0, current_req=%p exiting\n",
2995 current_req);
2996 pr_info("sect=%ld type=%x flags=%x\n",
2997 (long)blk_rq_pos(current_req), current_req->cmd_type,
2998 current_req->cmd_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 return;
3000 }
3001 if (test_bit(0, &fdc_busy)) {
3002 /* fdc busy, this new request will be treated when the
3003 current one is done */
3004 is_alive("do fd request, old request running");
3005 return;
3006 }
3007 lock_fdc(MAXTIMEOUT, 0);
3008 process_fd_request();
3009 is_alive("do fd request");
3010}
3011
3012static struct cont_t poll_cont = {
3013 .interrupt = success_and_wakeup,
3014 .redo = floppy_ready,
3015 .error = generic_failure,
3016 .done = generic_done
3017};
3018
3019static int poll_drive(int interruptible, int flag)
3020{
3021 int ret;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003022
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 /* no auto-sense, just clear dcl */
3024 raw_cmd = &default_raw_cmd;
3025 raw_cmd->flags = flag;
3026 raw_cmd->track = 0;
3027 raw_cmd->cmd_count = 0;
3028 cont = &poll_cont;
3029#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08003030 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 DPRINT("setting NEWCHANGE in poll_drive\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032#endif
3033 SETF(FD_DISK_NEWCHANGE);
3034 WAIT(floppy_ready);
3035 return ret;
3036}
3037
3038/*
3039 * User triggered reset
3040 * ====================
3041 */
3042
3043static void reset_intr(void)
3044{
Joe Perchesb46df352010-03-10 15:20:46 -08003045 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046}
3047
3048static struct cont_t reset_cont = {
3049 .interrupt = reset_intr,
3050 .redo = success_and_wakeup,
3051 .error = generic_failure,
3052 .done = generic_done
3053};
3054
3055static int user_reset_fdc(int drive, int arg, int interruptible)
3056{
3057 int ret;
3058
3059 ret = 0;
3060 LOCK_FDC(drive, interruptible);
3061 if (arg == FD_RESET_ALWAYS)
3062 FDCS->reset = 1;
3063 if (FDCS->reset) {
3064 cont = &reset_cont;
3065 WAIT(reset_fdc);
3066 }
3067 process_fd_request();
3068 return ret;
3069}
3070
3071/*
3072 * Misc Ioctl's and support
3073 * ========================
3074 */
3075static inline int fd_copyout(void __user *param, const void *address,
3076 unsigned long size)
3077{
3078 return copy_to_user(param, address, size) ? -EFAULT : 0;
3079}
3080
Joe Perches48c8cee2010-03-10 15:20:45 -08003081static inline int fd_copyin(void __user *param, void *address,
3082 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083{
3084 return copy_from_user(address, param, size) ? -EFAULT : 0;
3085}
3086
Joe Perches48c8cee2010-03-10 15:20:45 -08003087#define _COPYOUT(x) (copy_to_user((void __user *)param, &(x), sizeof(x)) \
3088 ? -EFAULT : 0)
3089#define _COPYIN(x) (copy_from_user(&(x), (void __user *)param, sizeof(x)) \
3090 ? -EFAULT : 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091
Joe Perches48c8cee2010-03-10 15:20:45 -08003092#define COPYOUT(x) ECALL(_COPYOUT(x))
3093#define COPYIN(x) ECALL(_COPYIN(x))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094
3095static inline const char *drive_name(int type, int drive)
3096{
3097 struct floppy_struct *floppy;
3098
3099 if (type)
3100 floppy = floppy_type + type;
3101 else {
3102 if (UDP->native_format)
3103 floppy = floppy_type + UDP->native_format;
3104 else
3105 return "(null)";
3106 }
3107 if (floppy->name)
3108 return floppy->name;
3109 else
3110 return "(null)";
3111}
3112
3113/* raw commands */
3114static void raw_cmd_done(int flag)
3115{
3116 int i;
3117
3118 if (!flag) {
3119 raw_cmd->flags |= FD_RAW_FAILURE;
3120 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3121 } else {
3122 raw_cmd->reply_count = inr;
3123 if (raw_cmd->reply_count > MAX_REPLIES)
3124 raw_cmd->reply_count = 0;
3125 for (i = 0; i < raw_cmd->reply_count; i++)
3126 raw_cmd->reply[i] = reply_buffer[i];
3127
3128 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3129 unsigned long flags;
3130 flags = claim_dma_lock();
3131 raw_cmd->length = fd_get_dma_residue();
3132 release_dma_lock(flags);
3133 }
3134
3135 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3136 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3137 raw_cmd->flags |= FD_RAW_FAILURE;
3138
3139 if (disk_change(current_drive))
3140 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3141 else
3142 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3143 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3144 motor_off_callback(current_drive);
3145
3146 if (raw_cmd->next &&
3147 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3148 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3149 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3150 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3151 raw_cmd = raw_cmd->next;
3152 return;
3153 }
3154 }
3155 generic_done(flag);
3156}
3157
3158static struct cont_t raw_cmd_cont = {
3159 .interrupt = success_and_wakeup,
3160 .redo = floppy_start,
3161 .error = generic_failure,
3162 .done = raw_cmd_done
3163};
3164
3165static inline int raw_cmd_copyout(int cmd, char __user *param,
3166 struct floppy_raw_cmd *ptr)
3167{
3168 int ret;
3169
3170 while (ptr) {
3171 COPYOUT(*ptr);
3172 param += sizeof(struct floppy_raw_cmd);
3173 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
3174 if (ptr->length >= 0
3175 && ptr->length <= ptr->buffer_length)
3176 ECALL(fd_copyout
3177 (ptr->data, ptr->kernel_data,
3178 ptr->buffer_length - ptr->length));
3179 }
3180 ptr = ptr->next;
3181 }
3182 return 0;
3183}
3184
3185static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3186{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003187 struct floppy_raw_cmd *next;
3188 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189
3190 this = *ptr;
3191 *ptr = NULL;
3192 while (this) {
3193 if (this->buffer_length) {
3194 fd_dma_mem_free((unsigned long)this->kernel_data,
3195 this->buffer_length);
3196 this->buffer_length = 0;
3197 }
3198 next = this->next;
3199 kfree(this);
3200 this = next;
3201 }
3202}
3203
3204static inline int raw_cmd_copyin(int cmd, char __user *param,
3205 struct floppy_raw_cmd **rcmd)
3206{
3207 struct floppy_raw_cmd *ptr;
3208 int ret;
3209 int i;
3210
3211 *rcmd = NULL;
3212 while (1) {
3213 ptr = (struct floppy_raw_cmd *)
3214 kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3215 if (!ptr)
3216 return -ENOMEM;
3217 *rcmd = ptr;
3218 COPYIN(*ptr);
3219 ptr->next = NULL;
3220 ptr->buffer_length = 0;
3221 param += sizeof(struct floppy_raw_cmd);
3222 if (ptr->cmd_count > 33)
3223 /* the command may now also take up the space
3224 * initially intended for the reply & the
3225 * reply count. Needed for long 82078 commands
3226 * such as RESTORE, which takes ... 17 command
3227 * bytes. Murphy's law #137: When you reserve
3228 * 16 bytes for a structure, you'll one day
3229 * discover that you really need 17...
3230 */
3231 return -EINVAL;
3232
3233 for (i = 0; i < 16; i++)
3234 ptr->reply[i] = 0;
3235 ptr->resultcode = 0;
3236 ptr->kernel_data = NULL;
3237
3238 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3239 if (ptr->length <= 0)
3240 return -EINVAL;
3241 ptr->kernel_data =
3242 (char *)fd_dma_mem_alloc(ptr->length);
3243 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3244 if (!ptr->kernel_data)
3245 return -ENOMEM;
3246 ptr->buffer_length = ptr->length;
3247 }
3248 if (ptr->flags & FD_RAW_WRITE)
3249 ECALL(fd_copyin(ptr->data, ptr->kernel_data,
3250 ptr->length));
3251 rcmd = &(ptr->next);
3252 if (!(ptr->flags & FD_RAW_MORE))
3253 return 0;
3254 ptr->rate &= 0x43;
3255 }
3256}
3257
3258static int raw_cmd_ioctl(int cmd, void __user *param)
3259{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003261 int drive;
3262 int ret2;
3263 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264
3265 if (FDCS->rawcmd <= 1)
3266 FDCS->rawcmd = 1;
3267 for (drive = 0; drive < N_DRIVE; drive++) {
3268 if (FDC(drive) != fdc)
3269 continue;
3270 if (drive == current_drive) {
3271 if (UDRS->fd_ref > 1) {
3272 FDCS->rawcmd = 2;
3273 break;
3274 }
3275 } else if (UDRS->fd_ref) {
3276 FDCS->rawcmd = 2;
3277 break;
3278 }
3279 }
3280
3281 if (FDCS->reset)
3282 return -EIO;
3283
3284 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3285 if (ret) {
3286 raw_cmd_free(&my_raw_cmd);
3287 return ret;
3288 }
3289
3290 raw_cmd = my_raw_cmd;
3291 cont = &raw_cmd_cont;
3292 ret = wait_til_done(floppy_start, 1);
3293#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08003294 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 DPRINT("calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296#endif
3297
3298 if (ret != -EINTR && FDCS->reset)
3299 ret = -EIO;
3300
3301 DRS->track = NO_TRACK;
3302
3303 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3304 if (!ret)
3305 ret = ret2;
3306 raw_cmd_free(&my_raw_cmd);
3307 return ret;
3308}
3309
3310static int invalidate_drive(struct block_device *bdev)
3311{
3312 /* invalidate the buffer track to force a reread */
3313 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3314 process_fd_request();
3315 check_disk_change(bdev);
3316 return 0;
3317}
3318
3319static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
3320 int drive, int type, struct block_device *bdev)
3321{
3322 int cnt;
3323
3324 /* sanity checking for parameters. */
3325 if (g->sect <= 0 ||
3326 g->head <= 0 ||
3327 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3328 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003329 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330 return -EINVAL;
3331 if (type) {
3332 if (!capable(CAP_SYS_ADMIN))
3333 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003334 mutex_lock(&open_lock);
Jiri Slaby8516a502009-06-30 11:41:44 -07003335 if (lock_fdc(drive, 1)) {
3336 mutex_unlock(&open_lock);
3337 return -EINTR;
3338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 floppy_type[type] = *g;
3340 floppy_type[type].name = "user format";
3341 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3342 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3343 floppy_type[type].size + 1;
3344 process_fd_request();
3345 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3346 struct block_device *bdev = opened_bdev[cnt];
3347 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3348 continue;
Christoph Hellwig2ef41632005-05-05 16:15:59 -07003349 __invalidate_device(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003351 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 } else {
3353 int oldStretch;
3354 LOCK_FDC(drive, 1);
3355 if (cmd != FDDEFPRM)
3356 /* notice a disk change immediately, else
3357 * we lose our settings immediately*/
3358 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3359 oldStretch = g->stretch;
3360 user_params[drive] = *g;
3361 if (buffer_drive == drive)
3362 SUPBOUND(buffer_max, user_params[drive].sect);
3363 current_type[drive] = &user_params[drive];
3364 floppy_sizes[drive] = user_params[drive].size;
3365 if (cmd == FDDEFPRM)
3366 DRS->keep_data = -1;
3367 else
3368 DRS->keep_data = 1;
3369 /* invalidation. Invalidate only when needed, i.e.
3370 * when there are already sectors in the buffer cache
3371 * whose number will change. This is useful, because
3372 * mtools often changes the geometry of the disk after
3373 * looking at the boot block */
3374 if (DRS->maxblock > user_params[drive].sect ||
3375 DRS->maxtrack ||
3376 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003377 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 invalidate_drive(bdev);
3379 else
3380 process_fd_request();
3381 }
3382 return 0;
3383}
3384
3385/* handle obsolete ioctl's */
3386static int ioctl_table[] = {
3387 FDCLRPRM,
3388 FDSETPRM,
3389 FDDEFPRM,
3390 FDGETPRM,
3391 FDMSGON,
3392 FDMSGOFF,
3393 FDFMTBEG,
3394 FDFMTTRK,
3395 FDFMTEND,
3396 FDSETEMSGTRESH,
3397 FDFLUSH,
3398 FDSETMAXERRS,
3399 FDGETMAXERRS,
3400 FDGETDRVTYP,
3401 FDSETDRVPRM,
3402 FDGETDRVPRM,
3403 FDGETDRVSTAT,
3404 FDPOLLDRVSTAT,
3405 FDRESET,
3406 FDGETFDCSTAT,
3407 FDWERRORCLR,
3408 FDWERRORGET,
3409 FDRAWCMD,
3410 FDEJECT,
3411 FDTWADDLE
3412};
3413
3414static inline int normalize_ioctl(int *cmd, int *size)
3415{
3416 int i;
3417
3418 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3419 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3420 *size = _IOC_SIZE(*cmd);
3421 *cmd = ioctl_table[i];
3422 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003423 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 return -EFAULT;
3425 }
3426 return 0;
3427 }
3428 }
3429 return -EINVAL;
3430}
3431
3432static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3433{
3434 if (type)
3435 *g = &floppy_type[type];
3436 else {
3437 LOCK_FDC(drive, 0);
3438 CALL(poll_drive(0, 0));
3439 process_fd_request();
3440 *g = current_type[drive];
3441 }
3442 if (!*g)
3443 return -ENODEV;
3444 return 0;
3445}
3446
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003447static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3448{
3449 int drive = (long)bdev->bd_disk->private_data;
3450 int type = ITYPE(drive_state[drive].fd_device);
3451 struct floppy_struct *g;
3452 int ret;
3453
3454 ret = get_floppy_geometry(drive, type, &g);
3455 if (ret)
3456 return ret;
3457
3458 geo->heads = g->head;
3459 geo->sectors = g->sect;
3460 geo->cylinders = g->track;
3461 return 0;
3462}
3463
Al Viroa4af9b42008-03-02 09:27:55 -05003464static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465 unsigned long param)
3466{
Al Viroa4af9b42008-03-02 09:27:55 -05003467#define FD_IOCTL_ALLOWED (mode & (FMODE_WRITE|FMODE_WRITE_IOCTL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468#define OUT(c,x) case c: outparam = (const char *) (x); break
3469#define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0
3470
Al Viroa4af9b42008-03-02 09:27:55 -05003471 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003472 int type = ITYPE(UDRS->fd_device);
3473 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 int ret;
3475 int size;
3476 union inparam {
3477 struct floppy_struct g; /* geometry */
3478 struct format_descr f;
3479 struct floppy_max_errors max_errors;
3480 struct floppy_drive_params dp;
3481 } inparam; /* parameters coming from user space */
3482 const char *outparam; /* parameters passed back to user space */
3483
3484 /* convert compatibility eject ioctls into floppy eject ioctl.
3485 * We do this in order to provide a means to eject floppy disks before
3486 * installing the new fdutils package */
3487 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003488 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 DPRINT("obsolete eject ioctl\n");
3490 DPRINT("please use floppycontrol --eject\n");
3491 cmd = FDEJECT;
3492 }
3493
Joe Perchesa81ee542010-03-10 15:20:46 -08003494 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495 return -EINVAL;
3496
Joe Perchesa81ee542010-03-10 15:20:46 -08003497 /* convert the old style command into a new style command */
3498 ECALL(normalize_ioctl(&cmd, &size));
3499
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 /* permission checks */
3501 if (((cmd & 0x40) && !FD_IOCTL_ALLOWED) ||
3502 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3503 return -EPERM;
3504
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003505 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3506 return -EINVAL;
3507
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508 /* copyin */
3509 CLEARSTRUCT(&inparam);
3510 if (_IOC_DIR(cmd) & _IOC_WRITE)
3511 ECALL(fd_copyin((void __user *)param, &inparam, size))
3512
3513 switch (cmd) {
3514 case FDEJECT:
3515 if (UDRS->fd_ref != 1)
3516 /* somebody else has this drive open */
3517 return -EBUSY;
3518 LOCK_FDC(drive, 1);
3519
3520 /* do the actual eject. Fails on
3521 * non-Sparc architectures */
3522 ret = fd_eject(UNIT(drive));
3523
3524 USETF(FD_DISK_CHANGED);
3525 USETF(FD_VERIFY);
3526 process_fd_request();
3527 return ret;
3528 case FDCLRPRM:
3529 LOCK_FDC(drive, 1);
3530 current_type[drive] = NULL;
3531 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3532 UDRS->keep_data = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003533 return invalidate_drive(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534 case FDSETPRM:
3535 case FDDEFPRM:
3536 return set_geometry(cmd, &inparam.g,
Al Viroa4af9b42008-03-02 09:27:55 -05003537 drive, type, bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538 case FDGETPRM:
3539 ECALL(get_floppy_geometry(drive, type,
3540 (struct floppy_struct **)
3541 &outparam));
3542 break;
3543
3544 case FDMSGON:
3545 UDP->flags |= FTD_MSG;
3546 return 0;
3547 case FDMSGOFF:
3548 UDP->flags &= ~FTD_MSG;
3549 return 0;
3550
3551 case FDFMTBEG:
3552 LOCK_FDC(drive, 1);
3553 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3554 ret = UDRS->flags;
3555 process_fd_request();
3556 if (ret & FD_VERIFY)
3557 return -ENODEV;
3558 if (!(ret & FD_DISK_WRITABLE))
3559 return -EROFS;
3560 return 0;
3561 case FDFMTTRK:
3562 if (UDRS->fd_ref != 1)
3563 return -EBUSY;
3564 return do_format(drive, &inparam.f);
3565 case FDFMTEND:
3566 case FDFLUSH:
3567 LOCK_FDC(drive, 1);
Al Viroa4af9b42008-03-02 09:27:55 -05003568 return invalidate_drive(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569
3570 case FDSETEMSGTRESH:
3571 UDP->max_errors.reporting =
3572 (unsigned short)(param & 0x0f);
3573 return 0;
3574 OUT(FDGETMAXERRS, &UDP->max_errors);
3575 IN(FDSETMAXERRS, &UDP->max_errors, max_errors);
3576
3577 case FDGETDRVTYP:
3578 outparam = drive_name(type, drive);
3579 SUPBOUND(size, strlen(outparam) + 1);
3580 break;
3581
3582 IN(FDSETDRVPRM, UDP, dp);
3583 OUT(FDGETDRVPRM, UDP);
3584
3585 case FDPOLLDRVSTAT:
3586 LOCK_FDC(drive, 1);
3587 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3588 process_fd_request();
3589 /* fall through */
3590 OUT(FDGETDRVSTAT, UDRS);
3591
3592 case FDRESET:
3593 return user_reset_fdc(drive, (int)param, 1);
3594
3595 OUT(FDGETFDCSTAT, UFDCS);
3596
3597 case FDWERRORCLR:
3598 CLEARSTRUCT(UDRWE);
3599 return 0;
3600 OUT(FDWERRORGET, UDRWE);
3601
3602 case FDRAWCMD:
3603 if (type)
3604 return -EINVAL;
3605 LOCK_FDC(drive, 1);
3606 set_floppy(drive);
3607 CALL(i = raw_cmd_ioctl(cmd, (void __user *)param));
3608 process_fd_request();
3609 return i;
3610
3611 case FDTWADDLE:
3612 LOCK_FDC(drive, 1);
3613 twaddle();
3614 process_fd_request();
3615 return 0;
3616
3617 default:
3618 return -EINVAL;
3619 }
3620
3621 if (_IOC_DIR(cmd) & _IOC_READ)
3622 return fd_copyout((void __user *)param, outparam, size);
3623 else
3624 return 0;
3625#undef OUT
3626#undef IN
3627}
3628
3629static void __init config_types(void)
3630{
Joe Perchesb46df352010-03-10 15:20:46 -08003631 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632 int drive;
3633
3634 /* read drive info out of physical CMOS */
3635 drive = 0;
3636 if (!UDP->cmos)
3637 UDP->cmos = FLOPPY0_TYPE;
3638 drive = 1;
3639 if (!UDP->cmos && FLOPPY1_TYPE)
3640 UDP->cmos = FLOPPY1_TYPE;
3641
Jesper Juhl06f748c2007-10-16 23:30:57 -07003642 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643
3644 for (drive = 0; drive < N_DRIVE; drive++) {
3645 unsigned int type = UDP->cmos;
3646 struct floppy_drive_params *params;
3647 const char *name = NULL;
3648 static char temparea[32];
3649
Tobias Klauser945f3902006-01-08 01:05:11 -08003650 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 params = &default_drive_params[type].params;
3652 if (type) {
3653 name = default_drive_params[type].name;
3654 allowed_drive_mask |= 1 << drive;
3655 } else
3656 allowed_drive_mask &= ~(1 << drive);
3657 } else {
3658 params = &default_drive_params[0].params;
3659 sprintf(temparea, "unknown type %d (usb?)", type);
3660 name = temparea;
3661 }
3662 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003663 const char *prepend;
3664 if (!has_drive) {
3665 prepend = "";
3666 has_drive = true;
3667 pr_info("Floppy drive(s):");
3668 } else {
3669 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 }
Joe Perchesb46df352010-03-10 15:20:46 -08003671
3672 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673 }
3674 *UDP = *params;
3675 }
Joe Perchesb46df352010-03-10 15:20:46 -08003676
3677 if (has_drive)
3678 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679}
3680
Al Viroa4af9b42008-03-02 09:27:55 -05003681static int floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682{
Al Viroa4af9b42008-03-02 09:27:55 -05003683 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003685 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686 if (UDRS->fd_ref < 0)
3687 UDRS->fd_ref = 0;
3688 else if (!UDRS->fd_ref--) {
3689 DPRINT("floppy_release with fd_ref == 0");
3690 UDRS->fd_ref = 0;
3691 }
3692 if (!UDRS->fd_ref)
3693 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003694 mutex_unlock(&open_lock);
Ingo Molnar3e541a42006-07-03 00:24:23 -07003695
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696 return 0;
3697}
3698
3699/*
3700 * floppy_open check for aliasing (/dev/fd0 can be the same as
3701 * /dev/PS0 etc), and disallows simultaneous access to the same
3702 * drive with different device numbers.
3703 */
Al Viroa4af9b42008-03-02 09:27:55 -05003704static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705{
Al Viroa4af9b42008-03-02 09:27:55 -05003706 int drive = (long)bdev->bd_disk->private_data;
3707 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 int try;
3709 int res = -EBUSY;
3710 char *tmp;
3711
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003712 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003714 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 goto out2;
3716
3717 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
3718 USETF(FD_DISK_CHANGED);
3719 USETF(FD_VERIFY);
3720 }
3721
Al Viroa4af9b42008-03-02 09:27:55 -05003722 if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723 goto out2;
3724
Al Viroa4af9b42008-03-02 09:27:55 -05003725 if (mode & FMODE_EXCL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726 UDRS->fd_ref = -1;
3727 else
3728 UDRS->fd_ref++;
3729
Al Viroa4af9b42008-03-02 09:27:55 -05003730 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731
3732 res = -ENXIO;
3733
3734 if (!floppy_track_buffer) {
3735 /* if opening an ED drive, reserve a big buffer,
3736 * else reserve a small one */
3737 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3738 try = 64; /* Only 48 actually useful */
3739 else
3740 try = 32; /* Only 24 actually useful */
3741
3742 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3743 if (!tmp && !floppy_track_buffer) {
3744 try >>= 1; /* buffer only one side */
3745 INFBOUND(try, 16);
3746 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3747 }
Joe Perchesa81ee542010-03-10 15:20:46 -08003748 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 if (!tmp && !floppy_track_buffer) {
3751 DPRINT("Unable to allocate DMA memory\n");
3752 goto out;
3753 }
3754 if (floppy_track_buffer) {
3755 if (tmp)
3756 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3757 } else {
3758 buffer_min = buffer_max = -1;
3759 floppy_track_buffer = tmp;
3760 max_buffer_sectors = try;
3761 }
3762 }
3763
Al Viroa4af9b42008-03-02 09:27:55 -05003764 new_dev = MINOR(bdev->bd_dev);
3765 UDRS->fd_device = new_dev;
3766 set_capacity(disks[drive], floppy_sizes[new_dev]);
3767 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 if (buffer_drive == drive)
3769 buffer_track = -1;
3770 }
3771
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772 if (UFDCS->rawcmd == 1)
3773 UFDCS->rawcmd = 2;
3774
Al Viroa4af9b42008-03-02 09:27:55 -05003775 if (!(mode & FMODE_NDELAY)) {
3776 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777 UDRS->last_checked = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003778 check_disk_change(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779 if (UTESTF(FD_DISK_CHANGED))
3780 goto out;
3781 }
3782 res = -EROFS;
Al Viroa4af9b42008-03-02 09:27:55 -05003783 if ((mode & FMODE_WRITE) && !(UTESTF(FD_DISK_WRITABLE)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784 goto out;
3785 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003786 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 return 0;
3788out:
3789 if (UDRS->fd_ref < 0)
3790 UDRS->fd_ref = 0;
3791 else
3792 UDRS->fd_ref--;
3793 if (!UDRS->fd_ref)
3794 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003796 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797 return res;
3798}
3799
3800/*
3801 * Check if the disk has been changed or if a change has been faked.
3802 */
3803static int check_floppy_change(struct gendisk *disk)
3804{
3805 int drive = (long)disk->private_data;
3806
3807 if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY))
3808 return 1;
3809
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003810 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811 lock_fdc(drive, 0);
3812 poll_drive(0, 0);
3813 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814 }
3815
3816 if (UTESTF(FD_DISK_CHANGED) ||
3817 UTESTF(FD_VERIFY) ||
3818 test_bit(drive, &fake_change) ||
3819 (!ITYPE(UDRS->fd_device) && !current_type[drive]))
3820 return 1;
3821 return 0;
3822}
3823
3824/*
3825 * This implements "read block 0" for floppy_revalidate().
3826 * Needed for format autodetection, checking whether there is
3827 * a disk in the drive, and whether that disk is writable.
3828 */
3829
NeilBrown6712ecf2007-09-27 12:47:43 +02003830static void floppy_rb0_complete(struct bio *bio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 int err)
3832{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833 complete((struct completion *)bio->bi_private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834}
3835
3836static int __floppy_read_block_0(struct block_device *bdev)
3837{
3838 struct bio bio;
3839 struct bio_vec bio_vec;
3840 struct completion complete;
3841 struct page *page;
3842 size_t size;
3843
3844 page = alloc_page(GFP_NOIO);
3845 if (!page) {
3846 process_fd_request();
3847 return -ENOMEM;
3848 }
3849
3850 size = bdev->bd_block_size;
3851 if (!size)
3852 size = 1024;
3853
3854 bio_init(&bio);
3855 bio.bi_io_vec = &bio_vec;
3856 bio_vec.bv_page = page;
3857 bio_vec.bv_len = size;
3858 bio_vec.bv_offset = 0;
3859 bio.bi_vcnt = 1;
3860 bio.bi_idx = 0;
3861 bio.bi_size = size;
3862 bio.bi_bdev = bdev;
3863 bio.bi_sector = 0;
3864 init_completion(&complete);
3865 bio.bi_private = &complete;
3866 bio.bi_end_io = floppy_rb0_complete;
3867
3868 submit_bio(READ, &bio);
3869 generic_unplug_device(bdev_get_queue(bdev));
3870 process_fd_request();
3871 wait_for_completion(&complete);
3872
3873 __free_page(page);
3874
3875 return 0;
3876}
3877
3878/* revalidate the floppy disk, i.e. trigger format autodetection by reading
3879 * the bootblock (block 0). "Autodetection" is also needed to check whether
3880 * there is a disk in the drive at all... Thus we also do it for fixed
3881 * geometry formats */
3882static int floppy_revalidate(struct gendisk *disk)
3883{
3884 int drive = (long)disk->private_data;
3885#define NO_GEOM (!current_type[drive] && !ITYPE(UDRS->fd_device))
3886 int cf;
3887 int res = 0;
3888
3889 if (UTESTF(FD_DISK_CHANGED) ||
3890 UTESTF(FD_VERIFY) || test_bit(drive, &fake_change) || NO_GEOM) {
3891 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08003892 pr_info("VFS: revalidate called on non-open device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 return -EFAULT;
3894 }
3895 lock_fdc(drive, 0);
3896 cf = UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY);
3897 if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)) {
3898 process_fd_request(); /*already done by another thread */
3899 return 0;
3900 }
3901 UDRS->maxblock = 0;
3902 UDRS->maxtrack = 0;
3903 if (buffer_drive == drive)
3904 buffer_track = -1;
3905 clear_bit(drive, &fake_change);
3906 UCLEARF(FD_DISK_CHANGED);
3907 if (cf)
3908 UDRS->generation++;
3909 if (NO_GEOM) {
3910 /* auto-sensing */
3911 res = __floppy_read_block_0(opened_bdev[drive]);
3912 } else {
3913 if (cf)
3914 poll_drive(0, FD_RAW_NEED_DISK);
3915 process_fd_request();
3916 }
3917 }
3918 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
3919 return res;
3920}
3921
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07003922static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07003923 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05003924 .open = floppy_open,
3925 .release = floppy_release,
3926 .locked_ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003927 .getgeo = fd_getgeo,
3928 .media_changed = check_floppy_change,
3929 .revalidate_disk = floppy_revalidate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932/*
3933 * Floppy Driver initialization
3934 * =============================
3935 */
3936
3937/* Determine the floppy disk controller type */
3938/* This routine was written by David C. Niemi */
3939static char __init get_fdc_version(void)
3940{
3941 int r;
3942
3943 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
3944 if (FDCS->reset)
3945 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003946 r = result();
3947 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948 return FDC_NONE; /* No FDC present ??? */
3949 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003950 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003951 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3952 }
3953 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003954 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3955 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 return FDC_UNKNOWN;
3957 }
3958
3959 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003960 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3962 }
3963
3964 output_byte(FD_PERPENDICULAR);
3965 if (need_more_output() == MORE_OUTPUT) {
3966 output_byte(0);
3967 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003968 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969 return FDC_82072A; /* 82072A as found on Sparcs. */
3970 }
3971
3972 output_byte(FD_UNLOCK);
3973 r = result();
3974 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003975 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003976 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 * LOCK/UNLOCK */
3978 }
3979 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003980 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3981 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982 return FDC_UNKNOWN;
3983 }
3984 output_byte(FD_PARTID);
3985 r = result();
3986 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003987 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3988 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 return FDC_UNKNOWN;
3990 }
3991 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003992 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 return FDC_82077; /* Revised 82077AA passes all the tests */
3994 }
3995 switch (reply_buffer[0] >> 5) {
3996 case 0x0:
3997 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08003998 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 return FDC_82078;
4000 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08004001 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002 return FDC_82078;
4003 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08004004 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 return FDC_S82078B;
4006 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08004007 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 return FDC_87306;
4009 default:
Joe Perchesb46df352010-03-10 15:20:46 -08004010 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
4011 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012 return FDC_82078_UNKN;
4013 }
4014} /* get_fdc_version */
4015
4016/* lilo configuration */
4017
4018static void __init floppy_set_flags(int *ints, int param, int param2)
4019{
4020 int i;
4021
4022 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4023 if (param)
4024 default_drive_params[i].params.flags |= param2;
4025 else
4026 default_drive_params[i].params.flags &= ~param2;
4027 }
4028 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
4029}
4030
4031static void __init daring(int *ints, int param, int param2)
4032{
4033 int i;
4034
4035 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4036 if (param) {
4037 default_drive_params[i].params.select_delay = 0;
4038 default_drive_params[i].params.flags |=
4039 FD_SILENT_DCL_CLEAR;
4040 } else {
4041 default_drive_params[i].params.select_delay =
4042 2 * HZ / 100;
4043 default_drive_params[i].params.flags &=
4044 ~FD_SILENT_DCL_CLEAR;
4045 }
4046 }
4047 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
4048}
4049
4050static void __init set_cmos(int *ints, int dummy, int dummy2)
4051{
4052 int current_drive = 0;
4053
4054 if (ints[0] != 2) {
4055 DPRINT("wrong number of parameters for CMOS\n");
4056 return;
4057 }
4058 current_drive = ints[1];
4059 if (current_drive < 0 || current_drive >= 8) {
4060 DPRINT("bad drive for set_cmos\n");
4061 return;
4062 }
4063#if N_FDC > 1
4064 if (current_drive >= 4 && !FDC2)
4065 FDC2 = 0x370;
4066#endif
4067 DP->cmos = ints[2];
4068 DPRINT("setting CMOS code to %d\n", ints[2]);
4069}
4070
4071static struct param_table {
4072 const char *name;
4073 void (*fn) (int *ints, int param, int param2);
4074 int *var;
4075 int def_param;
4076 int param2;
4077} config_params[] __initdata = {
4078 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4079 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4080 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4081 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4082 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4083 {"daring", daring, NULL, 1, 0},
4084#if N_FDC > 1
4085 {"two_fdc", NULL, &FDC2, 0x370, 0},
4086 {"one_fdc", NULL, &FDC2, 0, 0},
4087#endif
4088 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4089 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4090 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4091 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4092 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4093 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4094 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4095 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4096 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4097 {"nofifo", NULL, &no_fifo, 0x20, 0},
4098 {"usefifo", NULL, &no_fifo, 0, 0},
4099 {"cmos", set_cmos, NULL, 0, 0},
4100 {"slow", NULL, &slow_floppy, 1, 0},
4101 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4102 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4103 {"L40SX", NULL, &print_unex, 0, 0}
4104
4105 EXTRA_FLOPPY_PARAMS
4106};
4107
4108static int __init floppy_setup(char *str)
4109{
4110 int i;
4111 int param;
4112 int ints[11];
4113
4114 str = get_options(str, ARRAY_SIZE(ints), ints);
4115 if (str) {
4116 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4117 if (strcmp(str, config_params[i].name) == 0) {
4118 if (ints[0])
4119 param = ints[1];
4120 else
4121 param = config_params[i].def_param;
4122 if (config_params[i].fn)
4123 config_params[i].
4124 fn(ints, param,
4125 config_params[i].param2);
4126 if (config_params[i].var) {
4127 DPRINT("%s=%d\n", str, param);
4128 *config_params[i].var = param;
4129 }
4130 return 1;
4131 }
4132 }
4133 }
4134 if (str) {
4135 DPRINT("unknown floppy option [%s]\n", str);
4136
4137 DPRINT("allowed options are:");
4138 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004139 pr_cont(" %s", config_params[i].name);
4140 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141 } else
4142 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004143 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144 return 0;
4145}
4146
4147static int have_no_fdc = -ENODEV;
4148
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004149static ssize_t floppy_cmos_show(struct device *dev,
4150 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004151{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004152 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004153 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004154
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004155 drive = p->id;
4156 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004157}
Joe Perches48c8cee2010-03-10 15:20:45 -08004158
4159DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004160
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161static void floppy_device_release(struct device *dev)
4162{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163}
4164
Frans Popc90cd332009-07-25 22:24:54 +02004165static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004166{
4167 int fdc;
4168
4169 for (fdc = 0; fdc < N_FDC; fdc++)
4170 if (FDCS->address != -1)
4171 user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
4172
4173 return 0;
4174}
4175
Alexey Dobriyan47145212009-12-14 18:00:08 -08004176static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004177 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004178 .restore = floppy_resume,
4179};
4180
4181static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004182 .driver = {
4183 .name = "floppy",
Frans Popc90cd332009-07-25 22:24:54 +02004184 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004185 },
4186};
4187
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004188static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189
4190static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4191{
4192 int drive = (*part & 3) | ((*part & 0x80) >> 5);
4193 if (drive >= N_DRIVE ||
4194 !(allowed_drive_mask & (1 << drive)) ||
4195 fdc_state[FDC(drive)].version == FDC_NONE)
4196 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004197 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198 return NULL;
4199 *part = 0;
4200 return get_disk(disks[drive]);
4201}
4202
4203static int __init floppy_init(void)
4204{
4205 int i, unit, drive;
4206 int err, dr;
4207
Kumar Gala68e1ee62008-09-22 14:41:31 -07004208#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004209 if (check_legacy_ioport(FDC1))
4210 return -ENODEV;
4211#endif
4212
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 raw_cmd = NULL;
4214
4215 for (dr = 0; dr < N_DRIVE; dr++) {
4216 disks[dr] = alloc_disk(1);
4217 if (!disks[dr]) {
4218 err = -ENOMEM;
4219 goto out_put_disk;
4220 }
4221
4222 disks[dr]->major = FLOPPY_MAJOR;
4223 disks[dr]->first_minor = TOMINOR(dr);
4224 disks[dr]->fops = &floppy_fops;
4225 sprintf(disks[dr]->disk_name, "fd%d", dr);
4226
4227 init_timer(&motor_off_timer[dr]);
4228 motor_off_timer[dr].data = dr;
4229 motor_off_timer[dr].function = motor_off_callback;
4230 }
4231
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232 err = register_blkdev(FLOPPY_MAJOR, "fd");
4233 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004234 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004236 err = platform_driver_register(&floppy_driver);
4237 if (err)
4238 goto out_unreg_blkdev;
4239
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
4241 if (!floppy_queue) {
4242 err = -ENOMEM;
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004243 goto out_unreg_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244 }
Martin K. Petersen086fa5f2010-02-26 00:20:38 -05004245 blk_queue_max_hw_sectors(floppy_queue, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246
4247 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4248 floppy_find, NULL, NULL);
4249
4250 for (i = 0; i < 256; i++)
4251 if (ITYPE(i))
4252 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4253 else
4254 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4255
4256 reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
4257 config_types();
4258
4259 for (i = 0; i < N_FDC; i++) {
4260 fdc = i;
4261 CLEARSTRUCT(FDCS);
4262 FDCS->dtr = -1;
4263 FDCS->dor = 0x4;
4264#if defined(__sparc__) || defined(__mc68000__)
4265 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
4266#ifdef __mc68000__
4267 if (MACH_IS_SUN3X)
4268#endif
4269 FDCS->version = FDC_82072A;
4270#endif
4271 }
4272
4273 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274 fdc_state[0].address = FDC1;
4275 if (fdc_state[0].address == -1) {
4276 del_timer(&fd_timeout);
4277 err = -ENODEV;
4278 goto out_unreg_region;
4279 }
4280#if N_FDC > 1
4281 fdc_state[1].address = FDC2;
4282#endif
4283
4284 fdc = 0; /* reset fdc in case of unexpected interrupt */
4285 err = floppy_grab_irq_and_dma();
4286 if (err) {
4287 del_timer(&fd_timeout);
4288 err = -EBUSY;
4289 goto out_unreg_region;
4290 }
4291
4292 /* initialise drive state */
4293 for (drive = 0; drive < N_DRIVE; drive++) {
4294 CLEARSTRUCT(UDRS);
4295 CLEARSTRUCT(UDRWE);
4296 USETF(FD_DISK_NEWCHANGE);
4297 USETF(FD_DISK_CHANGED);
4298 USETF(FD_VERIFY);
4299 UDRS->fd_device = -1;
4300 floppy_track_buffer = NULL;
4301 max_buffer_sectors = 0;
4302 }
4303 /*
4304 * Small 10 msec delay to let through any interrupt that
4305 * initialization might have triggered, to not
4306 * confuse detection:
4307 */
4308 msleep(10);
4309
4310 for (i = 0; i < N_FDC; i++) {
4311 fdc = i;
4312 FDCS->driver_version = FD_DRIVER_VERSION;
4313 for (unit = 0; unit < 4; unit++)
4314 FDCS->track[unit] = 0;
4315 if (FDCS->address == -1)
4316 continue;
4317 FDCS->rawcmd = 2;
4318 if (user_reset_fdc(-1, FD_RESET_ALWAYS, 0)) {
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 FDCS->version = FDC_NONE;
4323 continue;
4324 }
4325 /* Try to determine the floppy controller type */
4326 FDCS->version = get_fdc_version();
4327 if (FDCS->version == FDC_NONE) {
4328 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004329 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 FDCS->address = -1;
4331 continue;
4332 }
4333 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4334 can_use_virtual_dma = 0;
4335
4336 have_no_fdc = 0;
4337 /* Not all FDCs seem to be able to handle the version command
4338 * properly, so force a reset for the standard FDC clones,
4339 * to avoid interrupt garbage.
4340 */
4341 user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
4342 }
4343 fdc = 0;
4344 del_timer(&fd_timeout);
4345 current_drive = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346 initialising = 0;
4347 if (have_no_fdc) {
4348 DPRINT("no floppy controllers found\n");
4349 err = have_no_fdc;
4350 goto out_flush_work;
4351 }
4352
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353 for (drive = 0; drive < N_DRIVE; drive++) {
4354 if (!(allowed_drive_mask & (1 << drive)))
4355 continue;
4356 if (fdc_state[FDC(drive)].version == FDC_NONE)
4357 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004358
4359 floppy_device[drive].name = floppy_device_name;
4360 floppy_device[drive].id = drive;
4361 floppy_device[drive].dev.release = floppy_device_release;
4362
4363 err = platform_device_register(&floppy_device[drive]);
4364 if (err)
4365 goto out_flush_work;
4366
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004367 err = device_create_file(&floppy_device[drive].dev,
4368 &dev_attr_cmos);
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004369 if (err)
4370 goto out_unreg_platform_dev;
4371
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372 /* to be cleaned up... */
4373 disks[drive]->private_data = (void *)(long)drive;
4374 disks[drive]->queue = floppy_queue;
4375 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004376 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 add_disk(disks[drive]);
4378 }
4379
4380 return 0;
4381
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004382out_unreg_platform_dev:
4383 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384out_flush_work:
4385 flush_scheduled_work();
4386 if (usage_count)
4387 floppy_release_irq_and_dma();
4388out_unreg_region:
4389 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4390 blk_cleanup_queue(floppy_queue);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004391out_unreg_driver:
4392 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393out_unreg_blkdev:
4394 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395out_put_disk:
4396 while (dr--) {
4397 del_timer(&motor_off_timer[dr]);
4398 put_disk(disks[dr]);
4399 }
4400 return err;
4401}
4402
4403static DEFINE_SPINLOCK(floppy_usage_lock);
4404
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004405static const struct io_region {
4406 int offset;
4407 int size;
4408} io_regions[] = {
4409 { 2, 1 },
4410 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4411 { 4, 2 },
4412 /* address + 6 is reserved, and may be taken by IDE.
4413 * Unfortunately, Adaptec doesn't know this :-(, */
4414 { 7, 1 },
4415};
4416
4417static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4418{
4419 while (p != io_regions) {
4420 p--;
4421 release_region(FDCS->address + p->offset, p->size);
4422 }
4423}
4424
4425#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4426
4427static int floppy_request_regions(int fdc)
4428{
4429 const struct io_region *p;
4430
4431 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
4432 if (!request_region(FDCS->address + p->offset, p->size, "floppy")) {
4433 DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address + p->offset);
4434 floppy_release_allocated_regions(fdc, p);
4435 return -EBUSY;
4436 }
4437 }
4438 return 0;
4439}
4440
4441static void floppy_release_regions(int fdc)
4442{
4443 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4444}
4445
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446static int floppy_grab_irq_and_dma(void)
4447{
4448 unsigned long flags;
4449
4450 spin_lock_irqsave(&floppy_usage_lock, flags);
4451 if (usage_count++) {
4452 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4453 return 0;
4454 }
4455 spin_unlock_irqrestore(&floppy_usage_lock, flags);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004456
4457 /*
4458 * We might have scheduled a free_irq(), wait it to
4459 * drain first:
4460 */
4461 flush_scheduled_work();
4462
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 if (fd_request_irq()) {
4464 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4465 FLOPPY_IRQ);
4466 spin_lock_irqsave(&floppy_usage_lock, flags);
4467 usage_count--;
4468 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4469 return -1;
4470 }
4471 if (fd_request_dma()) {
4472 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4473 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004474 if (can_use_virtual_dma & 2)
4475 use_virtual_dma = can_use_virtual_dma = 1;
4476 if (!(can_use_virtual_dma & 1)) {
4477 fd_free_irq();
4478 spin_lock_irqsave(&floppy_usage_lock, flags);
4479 usage_count--;
4480 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4481 return -1;
4482 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483 }
4484
4485 for (fdc = 0; fdc < N_FDC; fdc++) {
4486 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004487 if (floppy_request_regions(fdc))
4488 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489 }
4490 }
4491 for (fdc = 0; fdc < N_FDC; fdc++) {
4492 if (FDCS->address != -1) {
4493 reset_fdc_info(1);
4494 fd_outb(FDCS->dor, FD_DOR);
4495 }
4496 }
4497 fdc = 0;
4498 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4499
4500 for (fdc = 0; fdc < N_FDC; fdc++)
4501 if (FDCS->address != -1)
4502 fd_outb(FDCS->dor, FD_DOR);
4503 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004504 * The driver will try and free resources and relies on us
4505 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 */
4507 fdc = 0;
4508 irqdma_allocated = 1;
4509 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004510cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511 fd_free_irq();
4512 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004513 while (--fdc >= 0)
4514 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 spin_lock_irqsave(&floppy_usage_lock, flags);
4516 usage_count--;
4517 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4518 return -1;
4519}
4520
4521static void floppy_release_irq_and_dma(void)
4522{
4523 int old_fdc;
4524#ifdef FLOPPY_SANITY_CHECK
4525#ifndef __sparc__
4526 int drive;
4527#endif
4528#endif
4529 long tmpsize;
4530 unsigned long tmpaddr;
4531 unsigned long flags;
4532
4533 spin_lock_irqsave(&floppy_usage_lock, flags);
4534 if (--usage_count) {
4535 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4536 return;
4537 }
4538 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4539 if (irqdma_allocated) {
4540 fd_disable_dma();
4541 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004542 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543 irqdma_allocated = 0;
4544 }
4545 set_dor(0, ~0, 8);
4546#if N_FDC > 1
4547 set_dor(1, ~8, 0);
4548#endif
4549 floppy_enable_hlt();
4550
4551 if (floppy_track_buffer && max_buffer_sectors) {
4552 tmpsize = max_buffer_sectors * 1024;
4553 tmpaddr = (unsigned long)floppy_track_buffer;
4554 floppy_track_buffer = NULL;
4555 max_buffer_sectors = 0;
4556 buffer_min = buffer_max = -1;
4557 fd_dma_mem_free(tmpaddr, tmpsize);
4558 }
4559#ifdef FLOPPY_SANITY_CHECK
4560#ifndef __sparc__
4561 for (drive = 0; drive < N_FDC * 4; drive++)
4562 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004563 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564#endif
4565
4566 if (timer_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004567 pr_info("floppy timer still active:%s\n", timeout_message);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004569 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004570 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004571 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572#endif
4573 old_fdc = fdc;
4574 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004575 if (FDCS->address != -1)
4576 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577 fdc = old_fdc;
4578}
4579
4580#ifdef MODULE
4581
4582static char *floppy;
4583
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584static void __init parse_floppy_cfg_string(char *cfg)
4585{
4586 char *ptr;
4587
4588 while (*cfg) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004589 for (ptr = cfg; *cfg && *cfg != ' ' && *cfg != '\t'; cfg++)
4590 ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591 if (*cfg) {
4592 *cfg = '\0';
4593 cfg++;
4594 }
4595 if (*ptr)
4596 floppy_setup(ptr);
4597 }
4598}
4599
Jon Schindler7afea3b2008-04-29 00:59:21 -07004600static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601{
4602 if (floppy)
4603 parse_floppy_cfg_string(floppy);
4604 return floppy_init();
4605}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004606module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607
Jon Schindler7afea3b2008-04-29 00:59:21 -07004608static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609{
4610 int drive;
4611
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4613 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004614 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615
4616 for (drive = 0; drive < N_DRIVE; drive++) {
4617 del_timer_sync(&motor_off_timer[drive]);
4618
4619 if ((allowed_drive_mask & (1 << drive)) &&
4620 fdc_state[FDC(drive)].version != FDC_NONE) {
4621 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004622 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4623 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 }
4625 put_disk(disks[drive]);
4626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627
4628 del_timer_sync(&fd_timeout);
4629 del_timer_sync(&fd_timer);
4630 blk_cleanup_queue(floppy_queue);
4631
4632 if (usage_count)
4633 floppy_release_irq_and_dma();
4634
4635 /* eject disk, if any */
4636 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637}
Joe Perches48c8cee2010-03-10 15:20:45 -08004638
Jon Schindler7afea3b2008-04-29 00:59:21 -07004639module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640
4641module_param(floppy, charp, 0);
4642module_param(FLOPPY_IRQ, int, 0);
4643module_param(FLOPPY_DMA, int, 0);
4644MODULE_AUTHOR("Alain L. Knaff");
4645MODULE_SUPPORTED_DEVICE("fd");
4646MODULE_LICENSE("GPL");
4647
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004648/* This doesn't actually get used other than for module information */
4649static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004650 {"PNP0700", 0},
4651 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004652};
Joe Perches48c8cee2010-03-10 15:20:45 -08004653
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004654MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4655
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656#else
4657
4658__setup("floppy=", floppy_setup);
4659module_init(floppy_init)
4660#endif
4661
4662MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);