blob: 7d1cd21a0ebc07356774b2fa9c32a80b17a04f3d [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
1201#define LAST_OUT(x) if (output_byte(x)<0){ reset_fdc();return;}
1202
1203/* gets the response from the fdc */
1204static int result(void)
1205{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001206 int i;
1207 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208
1209 for (i = 0; i < MAX_REPLIES; i++) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001210 status = wait_til_ready();
1211 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 break;
1213 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1214 if ((status & ~STATUS_BUSY) == STATUS_READY) {
1215#ifdef FLOPPY_SANITY_CHECK
1216 resultjiffies = jiffies;
1217 resultsize = i;
1218#endif
1219 return i;
1220 }
1221 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1222 reply_buffer[i] = fd_inb(FD_DATA);
1223 else
1224 break;
1225 }
1226 if (!initialising) {
1227 DPRINT
1228 ("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1229 fdc, status, i);
1230 show_floppy();
1231 }
1232 FDCS->reset = 1;
1233 return -1;
1234}
1235
1236#define MORE_OUTPUT -2
1237/* does the fdc need more output? */
1238static int need_more_output(void)
1239{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001240 int status = wait_til_ready();
Jesper Juhl06f748c2007-10-16 23:30:57 -07001241
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001242 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 return -1;
1244 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY)
1245 return MORE_OUTPUT;
1246 return result();
1247}
1248
1249/* Set perpendicular mode as required, based on data rate, if supported.
1250 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1251 */
1252static inline void perpendicular_mode(void)
1253{
1254 unsigned char perp_mode;
1255
1256 if (raw_cmd->rate & 0x40) {
1257 switch (raw_cmd->rate & 3) {
1258 case 0:
1259 perp_mode = 2;
1260 break;
1261 case 3:
1262 perp_mode = 3;
1263 break;
1264 default:
1265 DPRINT("Invalid data rate for perpendicular mode!\n");
1266 cont->done(0);
1267 FDCS->reset = 1; /* convenient way to return to
1268 * redo without to much hassle (deep
1269 * stack et al. */
1270 return;
1271 }
1272 } else
1273 perp_mode = 0;
1274
1275 if (FDCS->perp_mode == perp_mode)
1276 return;
1277 if (FDCS->version >= FDC_82077_ORIG) {
1278 output_byte(FD_PERPENDICULAR);
1279 output_byte(perp_mode);
1280 FDCS->perp_mode = perp_mode;
1281 } else if (perp_mode) {
1282 DPRINT("perpendicular mode not supported by this FDC.\n");
1283 }
1284} /* perpendicular_mode */
1285
1286static int fifo_depth = 0xa;
1287static int no_fifo;
1288
1289static int fdc_configure(void)
1290{
1291 /* Turn on FIFO */
1292 output_byte(FD_CONFIGURE);
1293 if (need_more_output() != MORE_OUTPUT)
1294 return 0;
1295 output_byte(0);
1296 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1297 output_byte(0); /* pre-compensation from track
1298 0 upwards */
1299 return 1;
1300}
1301
1302#define NOMINAL_DTR 500
1303
1304/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1305 * head load time, and DMA disable flag to values needed by floppy.
1306 *
1307 * The value "dtr" is the data transfer rate in Kbps. It is needed
1308 * to account for the data rate-based scaling done by the 82072 and 82077
1309 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1310 * 8272a).
1311 *
1312 * Note that changing the data transfer rate has a (probably deleterious)
1313 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1314 * fdc_specify is called again after each data transfer rate
1315 * change.
1316 *
1317 * srt: 1000 to 16000 in microseconds
1318 * hut: 16 to 240 milliseconds
1319 * hlt: 2 to 254 milliseconds
1320 *
1321 * These values are rounded up to the next highest available delay time.
1322 */
1323static void fdc_specify(void)
1324{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001325 unsigned char spec1;
1326 unsigned char spec2;
1327 unsigned long srt;
1328 unsigned long hlt;
1329 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 unsigned long dtr = NOMINAL_DTR;
1331 unsigned long scale_dtr = NOMINAL_DTR;
1332 int hlt_max_code = 0x7f;
1333 int hut_max_code = 0xf;
1334
1335 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1336 fdc_configure();
1337 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 }
1339
1340 switch (raw_cmd->rate & 0x03) {
1341 case 3:
1342 dtr = 1000;
1343 break;
1344 case 1:
1345 dtr = 300;
1346 if (FDCS->version >= FDC_82078) {
1347 /* chose the default rate table, not the one
1348 * where 1 = 2 Mbps */
1349 output_byte(FD_DRIVESPEC);
1350 if (need_more_output() == MORE_OUTPUT) {
1351 output_byte(UNIT(current_drive));
1352 output_byte(0xc0);
1353 }
1354 }
1355 break;
1356 case 2:
1357 dtr = 250;
1358 break;
1359 }
1360
1361 if (FDCS->version >= FDC_82072) {
1362 scale_dtr = dtr;
1363 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1364 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1365 }
1366
1367 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001368 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001369 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001371
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 SUPBOUND(srt, 0xf);
1373 INFBOUND(srt, 0);
1374
Julia Lawall061837b2008-09-22 14:57:16 -07001375 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 if (hlt < 0x01)
1377 hlt = 0x01;
1378 else if (hlt > 0x7f)
1379 hlt = hlt_max_code;
1380
Julia Lawall061837b2008-09-22 14:57:16 -07001381 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 if (hut < 0x1)
1383 hut = 0x1;
1384 else if (hut > 0xf)
1385 hut = hut_max_code;
1386
1387 spec1 = (srt << 4) | hut;
1388 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1389
1390 /* If these parameters did not change, just return with success */
1391 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1392 /* Go ahead and set spec1 and spec2 */
1393 output_byte(FD_SPECIFY);
1394 output_byte(FDCS->spec1 = spec1);
1395 output_byte(FDCS->spec2 = spec2);
1396 }
1397} /* fdc_specify */
1398
1399/* Set the FDC's data transfer rate on behalf of the specified drive.
1400 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1401 * of the specify command (i.e. using the fdc_specify function).
1402 */
1403static int fdc_dtr(void)
1404{
1405 /* If data rate not already set to desired value, set it. */
1406 if ((raw_cmd->rate & 3) == FDCS->dtr)
1407 return 0;
1408
1409 /* Set dtr */
1410 fd_outb(raw_cmd->rate & 3, FD_DCR);
1411
1412 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1413 * need a stabilization period of several milliseconds to be
1414 * enforced after data rate changes before R/W operations.
1415 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1416 */
1417 FDCS->dtr = raw_cmd->rate & 3;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001418 return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
1419 (timeout_fn)floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420} /* fdc_dtr */
1421
1422static void tell_sector(void)
1423{
Joe Perchesb46df352010-03-10 15:20:46 -08001424 pr_cont(": track %d, head %d, sector %d, size %d",
1425 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426} /* tell_sector */
1427
Joe Perchesb46df352010-03-10 15:20:46 -08001428static void print_errors(void)
1429{
1430 DPRINT("");
1431 if (ST0 & ST0_ECE) {
1432 pr_cont("Recalibrate failed!");
1433 } else if (ST2 & ST2_CRC) {
1434 pr_cont("data CRC error");
1435 tell_sector();
1436 } else if (ST1 & ST1_CRC) {
1437 pr_cont("CRC error");
1438 tell_sector();
1439 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1440 (ST2 & ST2_MAM)) {
1441 if (!probing) {
1442 pr_cont("sector not found");
1443 tell_sector();
1444 } else
1445 pr_cont("probe failed...");
1446 } else if (ST2 & ST2_WC) { /* seek error */
1447 pr_cont("wrong cylinder");
1448 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1449 pr_cont("bad cylinder");
1450 } else {
1451 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1452 ST0, ST1, ST2);
1453 tell_sector();
1454 }
1455 pr_cont("\n");
1456}
1457
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458/*
1459 * OK, this error interpreting routine is called after a
1460 * DMA read/write has succeeded
1461 * or failed, so we check the results, and copy any buffers.
1462 * hhb: Added better error reporting.
1463 * ak: Made this into a separate routine.
1464 */
1465static int interpret_errors(void)
1466{
1467 char bad;
1468
1469 if (inr != 7) {
1470 DPRINT("-- FDC reply error");
1471 FDCS->reset = 1;
1472 return 1;
1473 }
1474
1475 /* check IC to find cause of interrupt */
1476 switch (ST0 & ST0_INTR) {
1477 case 0x40: /* error occurred during command execution */
1478 if (ST1 & ST1_EOC)
1479 return 0; /* occurs with pseudo-DMA */
1480 bad = 1;
1481 if (ST1 & ST1_WP) {
1482 DPRINT("Drive is write protected\n");
1483 CLEARF(FD_DISK_WRITABLE);
1484 cont->done(0);
1485 bad = 2;
1486 } else if (ST1 & ST1_ND) {
1487 SETF(FD_NEED_TWADDLE);
1488 } else if (ST1 & ST1_OR) {
1489 if (DP->flags & FTD_MSG)
1490 DPRINT("Over/Underrun - retrying\n");
1491 bad = 0;
1492 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001493 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 }
1495 if (ST2 & ST2_WC || ST2 & ST2_BC)
1496 /* wrong cylinder => recal */
1497 DRS->track = NEED_2_RECAL;
1498 return bad;
1499 case 0x80: /* invalid command given */
1500 DPRINT("Invalid FDC command given!\n");
1501 cont->done(0);
1502 return 2;
1503 case 0xc0:
1504 DPRINT("Abnormal termination caused by polling\n");
1505 cont->error();
1506 return 2;
1507 default: /* (0) Normal command termination */
1508 return 0;
1509 }
1510}
1511
1512/*
1513 * This routine is called when everything should be correctly set up
1514 * for the transfer (i.e. floppy motor is on, the correct floppy is
1515 * selected, and the head is sitting on the right track).
1516 */
1517static void setup_rw_floppy(void)
1518{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001519 int i;
1520 int r;
1521 int flags;
1522 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 unsigned long ready_date;
1524 timeout_fn function;
1525
1526 flags = raw_cmd->flags;
1527 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1528 flags |= FD_RAW_INTR;
1529
1530 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1531 ready_date = DRS->spinup_date + DP->spinup;
1532 /* If spinup will take a long time, rerun scandrives
1533 * again just before spinup completion. Beware that
1534 * after scandrives, we must again wait for selection.
1535 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001536 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 ready_date -= DP->select_delay;
1538 function = (timeout_fn) floppy_start;
1539 } else
1540 function = (timeout_fn) setup_rw_floppy;
1541
1542 /* wait until the floppy is spinning fast enough */
1543 if (fd_wait_for_completion(ready_date, function))
1544 return;
1545 }
1546 dflags = DRS->flags;
1547
1548 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1549 setup_DMA();
1550
1551 if (flags & FD_RAW_INTR)
1552 do_floppy = main_command_interrupt;
1553
1554 r = 0;
1555 for (i = 0; i < raw_cmd->cmd_count; i++)
1556 r |= output_byte(raw_cmd->cmd[i]);
1557
1558 debugt("rw_command: ");
1559
1560 if (r) {
1561 cont->error();
1562 reset_fdc();
1563 return;
1564 }
1565
1566 if (!(flags & FD_RAW_INTR)) {
1567 inr = result();
1568 cont->interrupt();
1569 } else if (flags & FD_RAW_NEED_DISK)
1570 fd_watchdog();
1571}
1572
1573static int blind_seek;
1574
1575/*
1576 * This is the routine called after every seek (or recalibrate) interrupt
1577 * from the floppy controller.
1578 */
1579static void seek_interrupt(void)
1580{
1581 debugt("seek interrupt:");
1582 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1583 DPRINT("seek failed\n");
1584 DRS->track = NEED_2_RECAL;
1585 cont->error();
1586 cont->redo();
1587 return;
1588 }
1589 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
1590#ifdef DCL_DEBUG
1591 if (DP->flags & FD_DEBUG) {
Joe Perchesb46df352010-03-10 15:20:46 -08001592 DPRINT("clearing NEWCHANGE flag because of effective seek\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 DPRINT("jiffies=%lu\n", jiffies);
1594 }
1595#endif
1596 CLEARF(FD_DISK_NEWCHANGE); /* effective seek */
1597 DRS->select_date = jiffies;
1598 }
1599 DRS->track = ST1;
1600 floppy_ready();
1601}
1602
1603static void check_wp(void)
1604{
1605 if (TESTF(FD_VERIFY)) {
1606 /* check write protection */
1607 output_byte(FD_GETSTATUS);
1608 output_byte(UNIT(current_drive));
1609 if (result() != 1) {
1610 FDCS->reset = 1;
1611 return;
1612 }
1613 CLEARF(FD_VERIFY);
1614 CLEARF(FD_NEED_TWADDLE);
1615#ifdef DCL_DEBUG
1616 if (DP->flags & FD_DEBUG) {
1617 DPRINT("checking whether disk is write protected\n");
1618 DPRINT("wp=%x\n", ST3 & 0x40);
1619 }
1620#endif
1621 if (!(ST3 & 0x40))
1622 SETF(FD_DISK_WRITABLE);
1623 else
1624 CLEARF(FD_DISK_WRITABLE);
1625 }
1626}
1627
1628static void seek_floppy(void)
1629{
1630 int track;
1631
1632 blind_seek = 0;
1633
1634#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08001635 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 DPRINT("calling disk change from seek\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637#endif
1638
1639 if (!TESTF(FD_DISK_NEWCHANGE) &&
1640 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1641 /* the media changed flag should be cleared after the seek.
1642 * If it isn't, this means that there is really no disk in
1643 * the drive.
1644 */
1645 SETF(FD_DISK_CHANGED);
1646 cont->done(0);
1647 cont->redo();
1648 return;
1649 }
1650 if (DRS->track <= NEED_1_RECAL) {
1651 recalibrate_floppy();
1652 return;
1653 } else if (TESTF(FD_DISK_NEWCHANGE) &&
1654 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1655 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1656 /* we seek to clear the media-changed condition. Does anybody
1657 * know a more elegant way, which works on all drives? */
1658 if (raw_cmd->track)
1659 track = raw_cmd->track - 1;
1660 else {
1661 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1662 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1663 blind_seek = 1;
1664 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1665 }
1666 track = 1;
1667 }
1668 } else {
1669 check_wp();
1670 if (raw_cmd->track != DRS->track &&
1671 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1672 track = raw_cmd->track;
1673 else {
1674 setup_rw_floppy();
1675 return;
1676 }
1677 }
1678
1679 do_floppy = seek_interrupt;
1680 output_byte(FD_SEEK);
1681 output_byte(UNIT(current_drive));
1682 LAST_OUT(track);
1683 debugt("seek command:");
1684}
1685
1686static void recal_interrupt(void)
1687{
1688 debugt("recal interrupt:");
1689 if (inr != 2)
1690 FDCS->reset = 1;
1691 else if (ST0 & ST0_ECE) {
1692 switch (DRS->track) {
1693 case NEED_1_RECAL:
1694 debugt("recal interrupt need 1 recal:");
1695 /* after a second recalibrate, we still haven't
1696 * reached track 0. Probably no drive. Raise an
1697 * error, as failing immediately might upset
1698 * computers possessed by the Devil :-) */
1699 cont->error();
1700 cont->redo();
1701 return;
1702 case NEED_2_RECAL:
1703 debugt("recal interrupt need 2 recal:");
1704 /* If we already did a recalibrate,
1705 * and we are not at track 0, this
1706 * means we have moved. (The only way
1707 * not to move at recalibration is to
1708 * be already at track 0.) Clear the
1709 * new change flag */
1710#ifdef DCL_DEBUG
Joe Perchesb46df352010-03-10 15:20:46 -08001711 if (DP->flags & FD_DEBUG)
1712 DPRINT("clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713#endif
1714
1715 CLEARF(FD_DISK_NEWCHANGE);
1716 DRS->select_date = jiffies;
1717 /* fall through */
1718 default:
1719 debugt("recal interrupt default:");
1720 /* Recalibrate moves the head by at
1721 * most 80 steps. If after one
1722 * recalibrate we don't have reached
1723 * track 0, this might mean that we
1724 * started beyond track 80. Try
1725 * again. */
1726 DRS->track = NEED_1_RECAL;
1727 break;
1728 }
1729 } else
1730 DRS->track = ST1;
1731 floppy_ready();
1732}
1733
1734static void print_result(char *message, int inr)
1735{
1736 int i;
1737
1738 DPRINT("%s ", message);
1739 if (inr >= 0)
1740 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001741 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1742 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743}
1744
1745/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001746irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 int do_print;
1749 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001750 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751
1752 lasthandler = handler;
1753 interruptjiffies = jiffies;
1754
1755 f = claim_dma_lock();
1756 fd_disable_dma();
1757 release_dma_lock(f);
1758
1759 floppy_enable_hlt();
1760 do_floppy = NULL;
1761 if (fdc >= N_FDC || FDCS->address == -1) {
1762 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001763 pr_info("DOR0=%x\n", fdc_state[0].dor);
1764 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
1765 pr_info("handler=%p\n", handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 is_alive("bizarre fdc");
1767 return IRQ_NONE;
1768 }
1769
1770 FDCS->reset = 0;
1771 /* We have to clear the reset flag here, because apparently on boxes
1772 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1773 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1774 * emission of the SENSEI's.
1775 * It is OK to emit floppy commands because we are in an interrupt
1776 * handler here, and thus we have to fear no interference of other
1777 * activity.
1778 */
1779
1780 do_print = !handler && print_unex && !initialising;
1781
1782 inr = result();
1783 if (do_print)
1784 print_result("unexpected interrupt", inr);
1785 if (inr == 0) {
1786 int max_sensei = 4;
1787 do {
1788 output_byte(FD_SENSEI);
1789 inr = result();
1790 if (do_print)
1791 print_result("sensei", inr);
1792 max_sensei--;
1793 } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2
1794 && max_sensei);
1795 }
1796 if (!handler) {
1797 FDCS->reset = 1;
1798 return IRQ_NONE;
1799 }
1800 schedule_bh(handler);
1801 is_alive("normal interrupt end");
1802
1803 /* FIXME! Was it really for us? */
1804 return IRQ_HANDLED;
1805}
1806
1807static void recalibrate_floppy(void)
1808{
1809 debugt("recalibrate floppy:");
1810 do_floppy = recal_interrupt;
1811 output_byte(FD_RECALIBRATE);
1812 LAST_OUT(UNIT(current_drive));
1813}
1814
1815/*
1816 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1817 */
1818static void reset_interrupt(void)
1819{
1820 debugt("reset interrupt:");
1821 result(); /* get the status ready for set_fdc */
1822 if (FDCS->reset) {
Joe Perchesb46df352010-03-10 15:20:46 -08001823 pr_info("reset set in interrupt, calling %p\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 cont->error(); /* a reset just after a reset. BAD! */
1825 }
1826 cont->redo();
1827}
1828
1829/*
1830 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1831 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1832 */
1833static void reset_fdc(void)
1834{
1835 unsigned long flags;
1836
1837 do_floppy = reset_interrupt;
1838 FDCS->reset = 0;
1839 reset_fdc_info(0);
1840
1841 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1842 /* Irrelevant for systems with true DMA (i386). */
1843
1844 flags = claim_dma_lock();
1845 fd_disable_dma();
1846 release_dma_lock(flags);
1847
1848 if (FDCS->version >= FDC_82072A)
1849 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1850 else {
1851 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1852 udelay(FD_RESET_DELAY);
1853 fd_outb(FDCS->dor, FD_DOR);
1854 }
1855}
1856
1857static void show_floppy(void)
1858{
1859 int i;
1860
Joe Perchesb46df352010-03-10 15:20:46 -08001861 pr_info("\n");
1862 pr_info("floppy driver state\n");
1863 pr_info("-------------------\n");
1864 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%p\n",
1865 jiffies, interruptjiffies, jiffies - interruptjiffies,
1866 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867
1868#ifdef FLOPPY_SANITY_CHECK
Joe Perchesb46df352010-03-10 15:20:46 -08001869 pr_info("timeout_message=%s\n", timeout_message);
1870 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001872 pr_info("%2x %2x %lu\n",
1873 output_log[(i + output_log_pos) % OLOGSIZE].data,
1874 output_log[(i + output_log_pos) % OLOGSIZE].status,
1875 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1876 pr_info("last result at %lu\n", resultjiffies);
1877 pr_info("last redo_fd_request at %lu\n", lastredo);
1878 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1879 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880#endif
1881
Joe Perchesb46df352010-03-10 15:20:46 -08001882 pr_info("status=%x\n", fd_inb(FD_STATUS));
1883 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 if (do_floppy)
Joe Perchesb46df352010-03-10 15:20:46 -08001885 pr_info("do_floppy=%p\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001886 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08001887 pr_info("floppy_work.func=%p\n", floppy_work.func);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08001889 pr_info("fd_timer.function=%p\n", fd_timer.function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 if (timer_pending(&fd_timeout)) {
Joe Perchesb46df352010-03-10 15:20:46 -08001891 pr_info("timer_function=%p\n", fd_timeout.function);
1892 pr_info("expires=%lu\n", fd_timeout.expires - jiffies);
1893 pr_info("now=%lu\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 }
Joe Perchesb46df352010-03-10 15:20:46 -08001895 pr_info("cont=%p\n", cont);
1896 pr_info("current_req=%p\n", current_req);
1897 pr_info("command_status=%d\n", command_status);
1898 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899}
1900
1901static void floppy_shutdown(unsigned long data)
1902{
1903 unsigned long flags;
1904
1905 if (!initialising)
1906 show_floppy();
1907 cancel_activity();
1908
1909 floppy_enable_hlt();
1910
1911 flags = claim_dma_lock();
1912 fd_disable_dma();
1913 release_dma_lock(flags);
1914
1915 /* avoid dma going to a random drive after shutdown */
1916
1917 if (!initialising)
1918 DPRINT("floppy timeout called\n");
1919 FDCS->reset = 1;
1920 if (cont) {
1921 cont->done(0);
1922 cont->redo(); /* this will recall reset when needed */
1923 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001924 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 process_fd_request();
1926 }
1927 is_alive("floppy shutdown");
1928}
1929
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001931static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001933 int mask;
1934 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935
1936 mask = 0xfc;
1937 data = UNIT(current_drive);
1938 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1939 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1940 set_debugt();
1941 /* no read since this drive is running */
1942 DRS->first_read_date = 0;
1943 /* note motor start time if motor is not yet running */
1944 DRS->spinup_date = jiffies;
1945 data |= (0x10 << UNIT(current_drive));
1946 }
1947 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1948 mask &= ~(0x10 << UNIT(current_drive));
1949
1950 /* starts motor and selects floppy */
1951 del_timer(motor_off_timer + current_drive);
1952 set_dor(fdc, mask, data);
1953
1954 /* wait_for_completion also schedules reset if needed. */
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001955 return fd_wait_for_completion(DRS->select_date + DP->select_delay,
1956 (timeout_fn)function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957}
1958
1959static void floppy_ready(void)
1960{
Joe Perches045f9832010-03-10 15:20:47 -08001961 if (FDCS->reset) {
1962 reset_fdc();
1963 return;
1964 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 if (start_motor(floppy_ready))
1966 return;
1967 if (fdc_dtr())
1968 return;
1969
1970#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08001971 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 DPRINT("calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973#endif
1974 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1975 disk_change(current_drive) && !DP->select_delay)
1976 twaddle(); /* this clears the dcl on certain drive/controller
1977 * combinations */
1978
1979#ifdef fd_chose_dma_mode
1980 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1981 unsigned long flags = claim_dma_lock();
1982 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1983 release_dma_lock(flags);
1984 }
1985#endif
1986
1987 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1988 perpendicular_mode();
1989 fdc_specify(); /* must be done here because of hut, hlt ... */
1990 seek_floppy();
1991 } else {
1992 if ((raw_cmd->flags & FD_RAW_READ) ||
1993 (raw_cmd->flags & FD_RAW_WRITE))
1994 fdc_specify();
1995 setup_rw_floppy();
1996 }
1997}
1998
1999static void floppy_start(void)
2000{
2001 reschedule_timeout(current_reqD, "floppy start", 0);
2002
2003 scandrives();
2004#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08002005 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 DPRINT("setting NEWCHANGE in floppy_start\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007#endif
2008 SETF(FD_DISK_NEWCHANGE);
2009 floppy_ready();
2010}
2011
2012/*
2013 * ========================================================================
2014 * here ends the bottom half. Exported routines are:
2015 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
2016 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
2017 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
2018 * and set_dor.
2019 * ========================================================================
2020 */
2021/*
2022 * General purpose continuations.
2023 * ==============================
2024 */
2025
2026static void do_wakeup(void)
2027{
2028 reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);
2029 cont = NULL;
2030 command_status += 2;
2031 wake_up(&command_done);
2032}
2033
2034static struct cont_t wakeup_cont = {
2035 .interrupt = empty,
2036 .redo = do_wakeup,
2037 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002038 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039};
2040
2041static struct cont_t intr_cont = {
2042 .interrupt = empty,
2043 .redo = process_fd_request,
2044 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002045 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046};
2047
Jesper Juhl06f748c2007-10-16 23:30:57 -07002048static int wait_til_done(void (*handler)(void), int interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049{
2050 int ret;
2051
2052 schedule_bh(handler);
2053
2054 if (command_status < 2 && NO_SIGNAL) {
2055 DECLARE_WAITQUEUE(wait, current);
2056
2057 add_wait_queue(&command_done, &wait);
2058 for (;;) {
2059 set_current_state(interruptible ?
2060 TASK_INTERRUPTIBLE :
2061 TASK_UNINTERRUPTIBLE);
2062
2063 if (command_status >= 2 || !NO_SIGNAL)
2064 break;
2065
2066 is_alive("wait_til_done");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 schedule();
2068 }
2069
2070 set_current_state(TASK_RUNNING);
2071 remove_wait_queue(&command_done, &wait);
2072 }
2073
2074 if (command_status < 2) {
2075 cancel_activity();
2076 cont = &intr_cont;
2077 reset_fdc();
2078 return -EINTR;
2079 }
2080
2081 if (FDCS->reset)
2082 command_status = FD_COMMAND_ERROR;
2083 if (command_status == FD_COMMAND_OKAY)
2084 ret = 0;
2085 else
2086 ret = -EIO;
2087 command_status = FD_COMMAND_NONE;
2088 return ret;
2089}
2090
2091static void generic_done(int result)
2092{
2093 command_status = result;
2094 cont = &wakeup_cont;
2095}
2096
2097static void generic_success(void)
2098{
2099 cont->done(1);
2100}
2101
2102static void generic_failure(void)
2103{
2104 cont->done(0);
2105}
2106
2107static void success_and_wakeup(void)
2108{
2109 generic_success();
2110 cont->redo();
2111}
2112
2113/*
2114 * formatting and rw support.
2115 * ==========================
2116 */
2117
2118static int next_valid_format(void)
2119{
2120 int probed_format;
2121
2122 probed_format = DRS->probed_format;
2123 while (1) {
2124 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2125 DRS->probed_format = 0;
2126 return 1;
2127 }
2128 if (floppy_type[DP->autodetect[probed_format]].sect) {
2129 DRS->probed_format = probed_format;
2130 return 0;
2131 }
2132 probed_format++;
2133 }
2134}
2135
2136static void bad_flp_intr(void)
2137{
2138 int err_count;
2139
2140 if (probing) {
2141 DRS->probed_format++;
2142 if (!next_valid_format())
2143 return;
2144 }
2145 err_count = ++(*errors);
2146 INFBOUND(DRWE->badness, err_count);
2147 if (err_count > DP->max_errors.abort)
2148 cont->done(0);
2149 if (err_count > DP->max_errors.reset)
2150 FDCS->reset = 1;
2151 else if (err_count > DP->max_errors.recal)
2152 DRS->track = NEED_2_RECAL;
2153}
2154
2155static void set_floppy(int drive)
2156{
2157 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002158
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 if (type)
2160 _floppy = floppy_type + type;
2161 else
2162 _floppy = current_type[drive];
2163}
2164
2165/*
2166 * formatting support.
2167 * ===================
2168 */
2169static void format_interrupt(void)
2170{
2171 switch (interpret_errors()) {
2172 case 1:
2173 cont->error();
2174 case 2:
2175 break;
2176 case 0:
2177 cont->done(1);
2178 }
2179 cont->redo();
2180}
2181
2182#define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2)
Joe Perches48c8cee2010-03-10 15:20:45 -08002183#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002185
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186static void setup_format_params(int track)
2187{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002188 int n;
2189 int il;
2190 int count;
2191 int head_shift;
2192 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 struct fparm {
2194 unsigned char track, head, sect, size;
2195 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196
2197 raw_cmd = &default_raw_cmd;
2198 raw_cmd->track = track;
2199
Joe Perches48c8cee2010-03-10 15:20:45 -08002200 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2201 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 raw_cmd->rate = _floppy->rate & 0x43;
2203 raw_cmd->cmd_count = NR_F;
2204 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2205 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2206 F_SIZECODE = FD_SIZECODE(_floppy);
2207 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2208 F_GAP = _floppy->fmt_gap;
2209 F_FILL = FD_FILL_BYTE;
2210
2211 raw_cmd->kernel_data = floppy_track_buffer;
2212 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2213
2214 /* allow for about 30ms for data transport per track */
2215 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2216
2217 /* a ``cylinder'' is two tracks plus a little stepping time */
2218 track_shift = 2 * head_shift + 3;
2219
2220 /* position of logical sector 1 on this track */
2221 n = (track_shift * format_req.track + head_shift * format_req.head)
2222 % F_SECT_PER_TRACK;
2223
2224 /* determine interleave */
2225 il = 1;
2226 if (_floppy->fmt_gap < 0x22)
2227 il++;
2228
2229 /* initialize field */
2230 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2231 here[count].track = format_req.track;
2232 here[count].head = format_req.head;
2233 here[count].sect = 0;
2234 here[count].size = F_SIZECODE;
2235 }
2236 /* place logical sectors */
2237 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2238 here[n].sect = count;
2239 n = (n + il) % F_SECT_PER_TRACK;
2240 if (here[n].sect) { /* sector busy, find next free sector */
2241 ++n;
2242 if (n >= F_SECT_PER_TRACK) {
2243 n -= F_SECT_PER_TRACK;
2244 while (here[n].sect)
2245 ++n;
2246 }
2247 }
2248 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002249 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002251 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 }
2253}
2254
2255static void redo_format(void)
2256{
2257 buffer_track = -1;
2258 setup_format_params(format_req.track << STRETCH(_floppy));
2259 floppy_start();
2260 debugt("queue format request");
2261}
2262
2263static struct cont_t format_cont = {
2264 .interrupt = format_interrupt,
2265 .redo = redo_format,
2266 .error = bad_flp_intr,
2267 .done = generic_done
2268};
2269
2270static int do_format(int drive, struct format_descr *tmp_format_req)
2271{
2272 int ret;
2273
2274 LOCK_FDC(drive, 1);
2275 set_floppy(drive);
2276 if (!_floppy ||
2277 _floppy->track > DP->tracks ||
2278 tmp_format_req->track >= _floppy->track ||
2279 tmp_format_req->head >= _floppy->head ||
2280 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2281 !_floppy->fmt_gap) {
2282 process_fd_request();
2283 return -EINVAL;
2284 }
2285 format_req = *tmp_format_req;
2286 format_errors = 0;
2287 cont = &format_cont;
2288 errors = &format_errors;
2289 IWAIT(redo_format);
2290 process_fd_request();
2291 return ret;
2292}
2293
2294/*
2295 * Buffer read/write and support
2296 * =============================
2297 */
2298
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002299static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300{
2301 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002302 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303
2304 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002305 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002306 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002307 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309
2310 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002311 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 current_req = NULL;
2313}
2314
2315/* new request_done. Can handle physical sectors which are smaller than a
2316 * logical buffer */
2317static void request_done(int uptodate)
2318{
2319 struct request_queue *q = floppy_queue;
2320 struct request *req = current_req;
2321 unsigned long flags;
2322 int block;
2323
2324 probing = 0;
Joe Perchesb46df352010-03-10 15:20:46 -08002325 reschedule_timeout(MAXTIMEOUT, "request done", uptodate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326
2327 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002328 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 return;
2330 }
2331
2332 if (uptodate) {
2333 /* maintain values for invalidation on geometry
2334 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002335 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 INFBOUND(DRS->maxblock, block);
2337 if (block > _floppy->sect)
2338 DRS->maxtrack = 1;
2339
2340 /* unlock chained buffers */
2341 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002342 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 spin_unlock_irqrestore(q->queue_lock, flags);
2344 } else {
2345 if (rq_data_dir(req) == WRITE) {
2346 /* record write error information */
2347 DRWE->write_errors++;
2348 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002349 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 DRWE->first_error_generation = DRS->generation;
2351 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002352 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 DRWE->last_error_generation = DRS->generation;
2354 }
2355 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002356 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 spin_unlock_irqrestore(q->queue_lock, flags);
2358 }
2359}
2360
2361/* Interrupt handler evaluating the result of the r/w operation */
2362static void rw_interrupt(void)
2363{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002364 int eoc;
2365 int ssize;
2366 int heads;
2367 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368
2369 if (R_HEAD >= 2) {
2370 /* some Toshiba floppy controllers occasionnally seem to
2371 * return bogus interrupts after read/write operations, which
2372 * can be recognized by a bad head number (>= 2) */
2373 return;
2374 }
2375
2376 if (!DRS->first_read_date)
2377 DRS->first_read_date = jiffies;
2378
2379 nr_sectors = 0;
2380 CODE2SIZE;
2381
2382 if (ST1 & ST1_EOC)
2383 eoc = 1;
2384 else
2385 eoc = 0;
2386
2387 if (COMMAND & 0x80)
2388 heads = 2;
2389 else
2390 heads = 1;
2391
2392 nr_sectors = (((R_TRACK - TRACK) * heads +
2393 R_HEAD - HEAD) * SECT_PER_TRACK +
2394 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2395
2396#ifdef FLOPPY_SANITY_CHECK
2397 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002398 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 DPRINT("long rw: %x instead of %lx\n",
2400 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002401 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2402 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2403 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2404 pr_info("heads=%d eoc=%d\n", heads, eoc);
2405 pr_info("spt=%d st=%d ss=%d\n",
2406 SECT_PER_TRACK, fsector_t, ssize);
2407 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 }
2409#endif
2410
2411 nr_sectors -= in_sector_offset;
2412 INFBOUND(nr_sectors, 0);
2413 SUPBOUND(current_count_sectors, nr_sectors);
2414
2415 switch (interpret_errors()) {
2416 case 2:
2417 cont->redo();
2418 return;
2419 case 1:
2420 if (!current_count_sectors) {
2421 cont->error();
2422 cont->redo();
2423 return;
2424 }
2425 break;
2426 case 0:
2427 if (!current_count_sectors) {
2428 cont->redo();
2429 return;
2430 }
2431 current_type[current_drive] = _floppy;
2432 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2433 break;
2434 }
2435
2436 if (probing) {
2437 if (DP->flags & FTD_MSG)
2438 DPRINT("Auto-detected floppy type %s in fd%d\n",
2439 _floppy->name, current_drive);
2440 current_type[current_drive] = _floppy;
2441 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2442 probing = 0;
2443 }
2444
2445 if (CT(COMMAND) != FD_READ ||
2446 raw_cmd->kernel_data == current_req->buffer) {
2447 /* transfer directly from buffer */
2448 cont->done(1);
2449 } else if (CT(COMMAND) == FD_READ) {
2450 buffer_track = raw_cmd->track;
2451 buffer_drive = current_drive;
2452 INFBOUND(buffer_max, nr_sectors + fsector_t);
2453 }
2454 cont->redo();
2455}
2456
2457/* Compute maximal contiguous buffer size. */
2458static int buffer_chain_size(void)
2459{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 struct bio_vec *bv;
NeilBrown5705f702007-09-25 12:35:59 +02002461 int size;
2462 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 char *base;
2464
2465 base = bio_data(current_req->bio);
2466 size = 0;
2467
NeilBrown5705f702007-09-25 12:35:59 +02002468 rq_for_each_segment(bv, current_req, iter) {
2469 if (page_address(bv->bv_page) + bv->bv_offset != base + size)
2470 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471
NeilBrown5705f702007-09-25 12:35:59 +02002472 size += bv->bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 }
2474
2475 return size >> 9;
2476}
2477
2478/* Compute the maximal transfer size */
2479static int transfer_size(int ssize, int max_sector, int max_size)
2480{
2481 SUPBOUND(max_sector, fsector_t + max_size);
2482
2483 /* alignment */
2484 max_sector -= (max_sector % _floppy->sect) % ssize;
2485
2486 /* transfer size, beginning not aligned */
2487 current_count_sectors = max_sector - fsector_t;
2488
2489 return max_sector;
2490}
2491
2492/*
2493 * Move data from/to the track buffer to/from the buffer cache.
2494 */
2495static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2496{
2497 int remaining; /* number of transferred 512-byte sectors */
2498 struct bio_vec *bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002499 char *buffer;
2500 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002501 int size;
2502 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503
2504 max_sector = transfer_size(ssize,
2505 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002506 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507
2508 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002509 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002511 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512
2513 remaining = current_count_sectors << 9;
2514#ifdef FLOPPY_SANITY_CHECK
Tejun Heo1011c1b2009-05-07 22:24:45 +09002515 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002517 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2518 pr_info("remaining=%d\n", remaining >> 9);
2519 pr_info("current_req->nr_sectors=%u\n",
2520 blk_rq_sectors(current_req));
2521 pr_info("current_req->current_nr_sectors=%u\n",
2522 blk_rq_cur_sectors(current_req));
2523 pr_info("max_sector=%d\n", max_sector);
2524 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 }
2526#endif
2527
2528 buffer_max = max(max_sector, buffer_max);
2529
2530 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2531
Tejun Heo1011c1b2009-05-07 22:24:45 +09002532 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533
NeilBrown5705f702007-09-25 12:35:59 +02002534 rq_for_each_segment(bv, current_req, iter) {
2535 if (!remaining)
2536 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537
NeilBrown5705f702007-09-25 12:35:59 +02002538 size = bv->bv_len;
2539 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540
NeilBrown5705f702007-09-25 12:35:59 +02002541 buffer = page_address(bv->bv_page) + bv->bv_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542#ifdef FLOPPY_SANITY_CHECK
NeilBrown5705f702007-09-25 12:35:59 +02002543 if (dma_buffer + size >
2544 floppy_track_buffer + (max_buffer_sectors << 10) ||
2545 dma_buffer < floppy_track_buffer) {
2546 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002547 (int)((floppy_track_buffer - dma_buffer) >> 9));
2548 pr_info("fsector_t=%d buffer_min=%d\n",
2549 fsector_t, buffer_min);
2550 pr_info("current_count_sectors=%ld\n",
2551 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002553 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002554 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002555 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002556 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 }
NeilBrown5705f702007-09-25 12:35:59 +02002558 if (((unsigned long)buffer) % 512)
2559 DPRINT("%p buffer not aligned\n", buffer);
2560#endif
2561 if (CT(COMMAND) == FD_READ)
2562 memcpy(buffer, dma_buffer, size);
2563 else
2564 memcpy(dma_buffer, buffer, size);
2565
2566 remaining -= size;
2567 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 }
2569#ifdef FLOPPY_SANITY_CHECK
2570 if (remaining) {
2571 if (remaining > 0)
2572 max_sector -= remaining >> 9;
2573 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2574 }
2575#endif
2576}
2577
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578/* work around a bug in pseudo DMA
2579 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2580 * sending data. Hence we need a different way to signal the
2581 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2582 * does not work with MT, hence we can only transfer one head at
2583 * a time
2584 */
2585static void virtualdmabug_workaround(void)
2586{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002587 int hard_sectors;
2588 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589
2590 if (CT(COMMAND) == FD_WRITE) {
2591 COMMAND &= ~0x80; /* switch off multiple track mode */
2592
2593 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2594 end_sector = SECTOR + hard_sectors - 1;
2595#ifdef FLOPPY_SANITY_CHECK
2596 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002597 pr_info("too many sectors %d > %d\n",
2598 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 return;
2600 }
2601#endif
Joe Perches48c8cee2010-03-10 15:20:45 -08002602 SECT_PER_TRACK = end_sector;
2603 /* make sure SECT_PER_TRACK
2604 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 }
2606}
2607
2608/*
2609 * Formulate a read/write request.
2610 * this routine decides where to load the data (directly to buffer, or to
2611 * tmp floppy area), how much data to load (the size of the buffer, the whole
2612 * track, or a single sector)
2613 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2614 * allocation on the fly, it should be done here. No other part should need
2615 * modification.
2616 */
2617
2618static int make_raw_rw_request(void)
2619{
2620 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002621 int max_sector;
2622 int max_size;
2623 int tracksize;
2624 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625
2626 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002627 pr_info("VFS: Block I/O scheduled on unopened device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 return 0;
2629 }
2630
2631 set_fdc((long)current_req->rq_disk->private_data);
2632
2633 raw_cmd = &default_raw_cmd;
2634 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
2635 FD_RAW_NEED_SEEK;
2636 raw_cmd->cmd_count = NR_RW;
2637 if (rq_data_dir(current_req) == READ) {
2638 raw_cmd->flags |= FD_RAW_READ;
2639 COMMAND = FM_MODE(_floppy, FD_READ);
2640 } else if (rq_data_dir(current_req) == WRITE) {
2641 raw_cmd->flags |= FD_RAW_WRITE;
2642 COMMAND = FM_MODE(_floppy, FD_WRITE);
2643 } else {
2644 DPRINT("make_raw_rw_request: unknown command\n");
2645 return 0;
2646 }
2647
2648 max_sector = _floppy->sect * _floppy->head;
2649
Tejun Heo83096eb2009-05-07 22:24:39 +09002650 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2651 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002653 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 current_count_sectors = 1;
2655 return 1;
2656 } else
2657 return 0;
2658 }
2659 HEAD = fsector_t / _floppy->sect;
2660
Keith Wansbrough9e491842008-09-22 14:57:17 -07002661 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 TESTF(FD_NEED_TWADDLE)) && fsector_t < _floppy->sect)
2663 max_sector = _floppy->sect;
2664
2665 /* 2M disks have phantom sectors on the first track */
2666 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2667 max_sector = 2 * _floppy->sect / 3;
2668 if (fsector_t >= max_sector) {
2669 current_count_sectors =
2670 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002671 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 return 1;
2673 }
2674 SIZECODE = 2;
2675 } else
2676 SIZECODE = FD_SIZECODE(_floppy);
2677 raw_cmd->rate = _floppy->rate & 0x43;
2678 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2679 raw_cmd->rate = 1;
2680
2681 if (SIZECODE)
2682 SIZECODE2 = 0xff;
2683 else
2684 SIZECODE2 = 0x80;
2685 raw_cmd->track = TRACK << STRETCH(_floppy);
2686 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2687 GAP = _floppy->gap;
2688 CODE2SIZE;
2689 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2690 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002691 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692
2693 /* tracksize describes the size which can be filled up with sectors
2694 * of size ssize.
2695 */
2696 tracksize = _floppy->sect - _floppy->sect % ssize;
2697 if (tracksize < _floppy->sect) {
2698 SECT_PER_TRACK++;
2699 if (tracksize <= fsector_t % _floppy->sect)
2700 SECTOR--;
2701
2702 /* if we are beyond tracksize, fill up using smaller sectors */
2703 while (tracksize <= fsector_t % _floppy->sect) {
2704 while (tracksize + ssize > _floppy->sect) {
2705 SIZECODE--;
2706 ssize >>= 1;
2707 }
2708 SECTOR++;
2709 SECT_PER_TRACK++;
2710 tracksize += ssize;
2711 }
2712 max_sector = HEAD * _floppy->sect + tracksize;
2713 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2714 max_sector = _floppy->sect;
2715 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2716 /* for virtual DMA bug workaround */
2717 max_sector = _floppy->sect;
2718 }
2719
2720 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2721 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002722 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 if ((raw_cmd->track == buffer_track) &&
2724 (current_drive == buffer_drive) &&
2725 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2726 /* data already in track buffer */
2727 if (CT(COMMAND) == FD_READ) {
2728 copy_buffer(1, max_sector, buffer_max);
2729 return 1;
2730 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002731 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 if (CT(COMMAND) == FD_WRITE) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002733 unsigned int sectors;
2734
2735 sectors = fsector_t + blk_rq_sectors(current_req);
2736 if (sectors > ssize && sectors < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 max_size = ssize + ssize;
2738 else
2739 max_size = ssize;
2740 }
2741 raw_cmd->flags &= ~FD_RAW_WRITE;
2742 raw_cmd->flags |= FD_RAW_READ;
2743 COMMAND = FM_MODE(_floppy, FD_READ);
2744 } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) {
2745 unsigned long dma_limit;
2746 int direct, indirect;
2747
2748 indirect =
2749 transfer_size(ssize, max_sector,
2750 max_buffer_sectors * 2) - fsector_t;
2751
2752 /*
2753 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2754 * on a 64 bit machine!
2755 */
2756 max_size = buffer_chain_size();
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002757 dma_limit = (MAX_DMA_ADDRESS -
2758 ((unsigned long)current_req->buffer)) >> 9;
Joe Perchesa81ee542010-03-10 15:20:46 -08002759 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 /* 64 kb boundaries */
2762 if (CROSS_64KB(current_req->buffer, max_size << 9))
2763 max_size = (K_64 -
2764 ((unsigned long)current_req->buffer) %
2765 K_64) >> 9;
2766 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2767 /*
2768 * We try to read tracks, but if we get too many errors, we
2769 * go back to reading just one sector at a time.
2770 *
2771 * This means we should be able to read a sector even if there
2772 * are other bad sectors on this track.
2773 */
2774 if (!direct ||
2775 (indirect * 2 > direct * 3 &&
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002776 *errors < DP->max_errors.read_track &&
2777 ((!probing ||
2778 (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002779 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 } else {
2781 raw_cmd->kernel_data = current_req->buffer;
2782 raw_cmd->length = current_count_sectors << 9;
2783 if (raw_cmd->length == 0) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002784 DPRINT("zero dma transfer attempted from make_raw_request\n");
2785 DPRINT("indirect=%d direct=%d fsector_t=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 indirect, direct, fsector_t);
2787 return 0;
2788 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 virtualdmabug_workaround();
2790 return 2;
2791 }
2792 }
2793
2794 if (CT(COMMAND) == FD_READ)
2795 max_size = max_sector; /* unbounded */
2796
2797 /* claim buffer track if needed */
2798 if (buffer_track != raw_cmd->track || /* bad track */
2799 buffer_drive != current_drive || /* bad drive */
2800 fsector_t > buffer_max ||
2801 fsector_t < buffer_min ||
2802 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002803 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 max_sector > 2 * max_buffer_sectors + buffer_min &&
2805 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)
2806 /* not enough space */
2807 ) {
2808 buffer_track = -1;
2809 buffer_drive = current_drive;
2810 buffer_max = buffer_min = aligned_sector_t;
2811 }
2812 raw_cmd->kernel_data = floppy_track_buffer +
2813 ((aligned_sector_t - buffer_min) << 9);
2814
2815 if (CT(COMMAND) == FD_WRITE) {
2816 /* copy write buffer to track buffer.
2817 * if we get here, we know that the write
2818 * is either aligned or the data already in the buffer
2819 * (buffer will be overwritten) */
2820#ifdef FLOPPY_SANITY_CHECK
2821 if (in_sector_offset && buffer_track == -1)
2822 DPRINT("internal error offset !=0 on write\n");
2823#endif
2824 buffer_track = raw_cmd->track;
2825 buffer_drive = current_drive;
2826 copy_buffer(ssize, max_sector,
2827 2 * max_buffer_sectors + buffer_min);
2828 } else
2829 transfer_size(ssize, max_sector,
2830 2 * max_buffer_sectors + buffer_min -
2831 aligned_sector_t);
2832
2833 /* round up current_count_sectors to get dma xfer size */
2834 raw_cmd->length = in_sector_offset + current_count_sectors;
2835 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2836 raw_cmd->length <<= 9;
2837#ifdef FLOPPY_SANITY_CHECK
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 if ((raw_cmd->length < current_count_sectors << 9) ||
2839 (raw_cmd->kernel_data != current_req->buffer &&
2840 CT(COMMAND) == FD_WRITE &&
2841 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2842 aligned_sector_t < buffer_min)) ||
2843 raw_cmd->length % (128 << SIZECODE) ||
2844 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2845 DPRINT("fractionary current count b=%lx s=%lx\n",
2846 raw_cmd->length, current_count_sectors);
2847 if (raw_cmd->kernel_data != current_req->buffer)
Joe Perchesb46df352010-03-10 15:20:46 -08002848 pr_info("addr=%d, length=%ld\n",
2849 (int)((raw_cmd->kernel_data -
2850 floppy_track_buffer) >> 9),
2851 current_count_sectors);
2852 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2853 fsector_t, aligned_sector_t, max_sector, max_size);
2854 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2855 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2856 COMMAND, SECTOR, HEAD, TRACK);
2857 pr_info("buffer drive=%d\n", buffer_drive);
2858 pr_info("buffer track=%d\n", buffer_track);
2859 pr_info("buffer_min=%d\n", buffer_min);
2860 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 return 0;
2862 }
2863
2864 if (raw_cmd->kernel_data != current_req->buffer) {
2865 if (raw_cmd->kernel_data < floppy_track_buffer ||
2866 current_count_sectors < 0 ||
2867 raw_cmd->length < 0 ||
2868 raw_cmd->kernel_data + raw_cmd->length >
2869 floppy_track_buffer + (max_buffer_sectors << 10)) {
2870 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002871 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2872 fsector_t, buffer_min, raw_cmd->length >> 9);
2873 pr_info("current_count_sectors=%ld\n",
2874 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002876 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002878 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 return 0;
2880 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002881 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002882 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 DPRINT("buffer overrun in direct transfer\n");
2884 return 0;
2885 } else if (raw_cmd->length < current_count_sectors << 9) {
2886 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002887 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2888 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889 }
2890 if (raw_cmd->length == 0) {
2891 DPRINT("zero dma transfer attempted from make_raw_request\n");
2892 return 0;
2893 }
2894#endif
2895
2896 virtualdmabug_workaround();
2897 return 2;
2898}
2899
2900static void redo_fd_request(void)
2901{
2902#define REPEAT {request_done(0); continue; }
2903 int drive;
2904 int tmp;
2905
2906 lastredo = jiffies;
2907 if (current_drive < N_DRIVE)
2908 floppy_off(current_drive);
2909
2910 for (;;) {
2911 if (!current_req) {
2912 struct request *req;
2913
2914 spin_lock_irq(floppy_queue->queue_lock);
Tejun Heo9934c8c2009-05-08 11:54:16 +09002915 req = blk_fetch_request(floppy_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 spin_unlock_irq(floppy_queue->queue_lock);
2917 if (!req) {
2918 do_floppy = NULL;
2919 unlock_fdc();
2920 return;
2921 }
2922 current_req = req;
2923 }
2924 drive = (long)current_req->rq_disk->private_data;
2925 set_fdc(drive);
2926 reschedule_timeout(current_reqD, "redo fd request", 0);
2927
2928 set_floppy(drive);
2929 raw_cmd = &default_raw_cmd;
2930 raw_cmd->flags = 0;
2931 if (start_motor(redo_fd_request))
2932 return;
2933 disk_change(current_drive);
2934 if (test_bit(current_drive, &fake_change) ||
2935 TESTF(FD_DISK_CHANGED)) {
2936 DPRINT("disk absent or changed during operation\n");
2937 REPEAT;
2938 }
2939 if (!_floppy) { /* Autodetection */
2940 if (!probing) {
2941 DRS->probed_format = 0;
2942 if (next_valid_format()) {
2943 DPRINT("no autodetectable formats\n");
2944 _floppy = NULL;
2945 REPEAT;
2946 }
2947 }
2948 probing = 1;
2949 _floppy =
2950 floppy_type + DP->autodetect[DRS->probed_format];
2951 } else
2952 probing = 0;
2953 errors = &(current_req->errors);
2954 tmp = make_raw_rw_request();
2955 if (tmp < 2) {
2956 request_done(tmp);
2957 continue;
2958 }
2959
2960 if (TESTF(FD_NEED_TWADDLE))
2961 twaddle();
2962 schedule_bh(floppy_start);
2963 debugt("queue fd request");
2964 return;
2965 }
2966#undef REPEAT
2967}
2968
2969static struct cont_t rw_cont = {
2970 .interrupt = rw_interrupt,
2971 .redo = redo_fd_request,
2972 .error = bad_flp_intr,
2973 .done = request_done
2974};
2975
2976static void process_fd_request(void)
2977{
2978 cont = &rw_cont;
2979 schedule_bh(redo_fd_request);
2980}
2981
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002982static void do_fd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983{
2984 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002985 pr_info("VFS: do_fd_request called on non-open device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 return;
2987 }
2988
2989 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002990 pr_info("warning: usage count=0, current_req=%p exiting\n",
2991 current_req);
2992 pr_info("sect=%ld type=%x flags=%x\n",
2993 (long)blk_rq_pos(current_req), current_req->cmd_type,
2994 current_req->cmd_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 return;
2996 }
2997 if (test_bit(0, &fdc_busy)) {
2998 /* fdc busy, this new request will be treated when the
2999 current one is done */
3000 is_alive("do fd request, old request running");
3001 return;
3002 }
3003 lock_fdc(MAXTIMEOUT, 0);
3004 process_fd_request();
3005 is_alive("do fd request");
3006}
3007
3008static struct cont_t poll_cont = {
3009 .interrupt = success_and_wakeup,
3010 .redo = floppy_ready,
3011 .error = generic_failure,
3012 .done = generic_done
3013};
3014
3015static int poll_drive(int interruptible, int flag)
3016{
3017 int ret;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003018
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019 /* no auto-sense, just clear dcl */
3020 raw_cmd = &default_raw_cmd;
3021 raw_cmd->flags = flag;
3022 raw_cmd->track = 0;
3023 raw_cmd->cmd_count = 0;
3024 cont = &poll_cont;
3025#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08003026 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 DPRINT("setting NEWCHANGE in poll_drive\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028#endif
3029 SETF(FD_DISK_NEWCHANGE);
3030 WAIT(floppy_ready);
3031 return ret;
3032}
3033
3034/*
3035 * User triggered reset
3036 * ====================
3037 */
3038
3039static void reset_intr(void)
3040{
Joe Perchesb46df352010-03-10 15:20:46 -08003041 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042}
3043
3044static struct cont_t reset_cont = {
3045 .interrupt = reset_intr,
3046 .redo = success_and_wakeup,
3047 .error = generic_failure,
3048 .done = generic_done
3049};
3050
3051static int user_reset_fdc(int drive, int arg, int interruptible)
3052{
3053 int ret;
3054
3055 ret = 0;
3056 LOCK_FDC(drive, interruptible);
3057 if (arg == FD_RESET_ALWAYS)
3058 FDCS->reset = 1;
3059 if (FDCS->reset) {
3060 cont = &reset_cont;
3061 WAIT(reset_fdc);
3062 }
3063 process_fd_request();
3064 return ret;
3065}
3066
3067/*
3068 * Misc Ioctl's and support
3069 * ========================
3070 */
3071static inline int fd_copyout(void __user *param, const void *address,
3072 unsigned long size)
3073{
3074 return copy_to_user(param, address, size) ? -EFAULT : 0;
3075}
3076
Joe Perches48c8cee2010-03-10 15:20:45 -08003077static inline int fd_copyin(void __user *param, void *address,
3078 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079{
3080 return copy_from_user(address, param, size) ? -EFAULT : 0;
3081}
3082
Joe Perches48c8cee2010-03-10 15:20:45 -08003083#define _COPYOUT(x) (copy_to_user((void __user *)param, &(x), sizeof(x)) \
3084 ? -EFAULT : 0)
3085#define _COPYIN(x) (copy_from_user(&(x), (void __user *)param, sizeof(x)) \
3086 ? -EFAULT : 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087
Joe Perches48c8cee2010-03-10 15:20:45 -08003088#define COPYOUT(x) ECALL(_COPYOUT(x))
3089#define COPYIN(x) ECALL(_COPYIN(x))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090
3091static inline const char *drive_name(int type, int drive)
3092{
3093 struct floppy_struct *floppy;
3094
3095 if (type)
3096 floppy = floppy_type + type;
3097 else {
3098 if (UDP->native_format)
3099 floppy = floppy_type + UDP->native_format;
3100 else
3101 return "(null)";
3102 }
3103 if (floppy->name)
3104 return floppy->name;
3105 else
3106 return "(null)";
3107}
3108
3109/* raw commands */
3110static void raw_cmd_done(int flag)
3111{
3112 int i;
3113
3114 if (!flag) {
3115 raw_cmd->flags |= FD_RAW_FAILURE;
3116 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3117 } else {
3118 raw_cmd->reply_count = inr;
3119 if (raw_cmd->reply_count > MAX_REPLIES)
3120 raw_cmd->reply_count = 0;
3121 for (i = 0; i < raw_cmd->reply_count; i++)
3122 raw_cmd->reply[i] = reply_buffer[i];
3123
3124 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3125 unsigned long flags;
3126 flags = claim_dma_lock();
3127 raw_cmd->length = fd_get_dma_residue();
3128 release_dma_lock(flags);
3129 }
3130
3131 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3132 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3133 raw_cmd->flags |= FD_RAW_FAILURE;
3134
3135 if (disk_change(current_drive))
3136 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3137 else
3138 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3139 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3140 motor_off_callback(current_drive);
3141
3142 if (raw_cmd->next &&
3143 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3144 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3145 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3146 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3147 raw_cmd = raw_cmd->next;
3148 return;
3149 }
3150 }
3151 generic_done(flag);
3152}
3153
3154static struct cont_t raw_cmd_cont = {
3155 .interrupt = success_and_wakeup,
3156 .redo = floppy_start,
3157 .error = generic_failure,
3158 .done = raw_cmd_done
3159};
3160
3161static inline int raw_cmd_copyout(int cmd, char __user *param,
3162 struct floppy_raw_cmd *ptr)
3163{
3164 int ret;
3165
3166 while (ptr) {
3167 COPYOUT(*ptr);
3168 param += sizeof(struct floppy_raw_cmd);
3169 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
3170 if (ptr->length >= 0
3171 && ptr->length <= ptr->buffer_length)
3172 ECALL(fd_copyout
3173 (ptr->data, ptr->kernel_data,
3174 ptr->buffer_length - ptr->length));
3175 }
3176 ptr = ptr->next;
3177 }
3178 return 0;
3179}
3180
3181static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3182{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003183 struct floppy_raw_cmd *next;
3184 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185
3186 this = *ptr;
3187 *ptr = NULL;
3188 while (this) {
3189 if (this->buffer_length) {
3190 fd_dma_mem_free((unsigned long)this->kernel_data,
3191 this->buffer_length);
3192 this->buffer_length = 0;
3193 }
3194 next = this->next;
3195 kfree(this);
3196 this = next;
3197 }
3198}
3199
3200static inline int raw_cmd_copyin(int cmd, char __user *param,
3201 struct floppy_raw_cmd **rcmd)
3202{
3203 struct floppy_raw_cmd *ptr;
3204 int ret;
3205 int i;
3206
3207 *rcmd = NULL;
3208 while (1) {
3209 ptr = (struct floppy_raw_cmd *)
3210 kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3211 if (!ptr)
3212 return -ENOMEM;
3213 *rcmd = ptr;
3214 COPYIN(*ptr);
3215 ptr->next = NULL;
3216 ptr->buffer_length = 0;
3217 param += sizeof(struct floppy_raw_cmd);
3218 if (ptr->cmd_count > 33)
3219 /* the command may now also take up the space
3220 * initially intended for the reply & the
3221 * reply count. Needed for long 82078 commands
3222 * such as RESTORE, which takes ... 17 command
3223 * bytes. Murphy's law #137: When you reserve
3224 * 16 bytes for a structure, you'll one day
3225 * discover that you really need 17...
3226 */
3227 return -EINVAL;
3228
3229 for (i = 0; i < 16; i++)
3230 ptr->reply[i] = 0;
3231 ptr->resultcode = 0;
3232 ptr->kernel_data = NULL;
3233
3234 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3235 if (ptr->length <= 0)
3236 return -EINVAL;
3237 ptr->kernel_data =
3238 (char *)fd_dma_mem_alloc(ptr->length);
3239 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3240 if (!ptr->kernel_data)
3241 return -ENOMEM;
3242 ptr->buffer_length = ptr->length;
3243 }
3244 if (ptr->flags & FD_RAW_WRITE)
3245 ECALL(fd_copyin(ptr->data, ptr->kernel_data,
3246 ptr->length));
3247 rcmd = &(ptr->next);
3248 if (!(ptr->flags & FD_RAW_MORE))
3249 return 0;
3250 ptr->rate &= 0x43;
3251 }
3252}
3253
3254static int raw_cmd_ioctl(int cmd, void __user *param)
3255{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003257 int drive;
3258 int ret2;
3259 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260
3261 if (FDCS->rawcmd <= 1)
3262 FDCS->rawcmd = 1;
3263 for (drive = 0; drive < N_DRIVE; drive++) {
3264 if (FDC(drive) != fdc)
3265 continue;
3266 if (drive == current_drive) {
3267 if (UDRS->fd_ref > 1) {
3268 FDCS->rawcmd = 2;
3269 break;
3270 }
3271 } else if (UDRS->fd_ref) {
3272 FDCS->rawcmd = 2;
3273 break;
3274 }
3275 }
3276
3277 if (FDCS->reset)
3278 return -EIO;
3279
3280 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3281 if (ret) {
3282 raw_cmd_free(&my_raw_cmd);
3283 return ret;
3284 }
3285
3286 raw_cmd = my_raw_cmd;
3287 cont = &raw_cmd_cont;
3288 ret = wait_til_done(floppy_start, 1);
3289#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08003290 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291 DPRINT("calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292#endif
3293
3294 if (ret != -EINTR && FDCS->reset)
3295 ret = -EIO;
3296
3297 DRS->track = NO_TRACK;
3298
3299 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3300 if (!ret)
3301 ret = ret2;
3302 raw_cmd_free(&my_raw_cmd);
3303 return ret;
3304}
3305
3306static int invalidate_drive(struct block_device *bdev)
3307{
3308 /* invalidate the buffer track to force a reread */
3309 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3310 process_fd_request();
3311 check_disk_change(bdev);
3312 return 0;
3313}
3314
3315static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
3316 int drive, int type, struct block_device *bdev)
3317{
3318 int cnt;
3319
3320 /* sanity checking for parameters. */
3321 if (g->sect <= 0 ||
3322 g->head <= 0 ||
3323 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3324 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003325 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 return -EINVAL;
3327 if (type) {
3328 if (!capable(CAP_SYS_ADMIN))
3329 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003330 mutex_lock(&open_lock);
Jiri Slaby8516a502009-06-30 11:41:44 -07003331 if (lock_fdc(drive, 1)) {
3332 mutex_unlock(&open_lock);
3333 return -EINTR;
3334 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335 floppy_type[type] = *g;
3336 floppy_type[type].name = "user format";
3337 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3338 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3339 floppy_type[type].size + 1;
3340 process_fd_request();
3341 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3342 struct block_device *bdev = opened_bdev[cnt];
3343 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3344 continue;
Christoph Hellwig2ef41632005-05-05 16:15:59 -07003345 __invalidate_device(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003347 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348 } else {
3349 int oldStretch;
3350 LOCK_FDC(drive, 1);
3351 if (cmd != FDDEFPRM)
3352 /* notice a disk change immediately, else
3353 * we lose our settings immediately*/
3354 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3355 oldStretch = g->stretch;
3356 user_params[drive] = *g;
3357 if (buffer_drive == drive)
3358 SUPBOUND(buffer_max, user_params[drive].sect);
3359 current_type[drive] = &user_params[drive];
3360 floppy_sizes[drive] = user_params[drive].size;
3361 if (cmd == FDDEFPRM)
3362 DRS->keep_data = -1;
3363 else
3364 DRS->keep_data = 1;
3365 /* invalidation. Invalidate only when needed, i.e.
3366 * when there are already sectors in the buffer cache
3367 * whose number will change. This is useful, because
3368 * mtools often changes the geometry of the disk after
3369 * looking at the boot block */
3370 if (DRS->maxblock > user_params[drive].sect ||
3371 DRS->maxtrack ||
3372 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003373 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374 invalidate_drive(bdev);
3375 else
3376 process_fd_request();
3377 }
3378 return 0;
3379}
3380
3381/* handle obsolete ioctl's */
3382static int ioctl_table[] = {
3383 FDCLRPRM,
3384 FDSETPRM,
3385 FDDEFPRM,
3386 FDGETPRM,
3387 FDMSGON,
3388 FDMSGOFF,
3389 FDFMTBEG,
3390 FDFMTTRK,
3391 FDFMTEND,
3392 FDSETEMSGTRESH,
3393 FDFLUSH,
3394 FDSETMAXERRS,
3395 FDGETMAXERRS,
3396 FDGETDRVTYP,
3397 FDSETDRVPRM,
3398 FDGETDRVPRM,
3399 FDGETDRVSTAT,
3400 FDPOLLDRVSTAT,
3401 FDRESET,
3402 FDGETFDCSTAT,
3403 FDWERRORCLR,
3404 FDWERRORGET,
3405 FDRAWCMD,
3406 FDEJECT,
3407 FDTWADDLE
3408};
3409
3410static inline int normalize_ioctl(int *cmd, int *size)
3411{
3412 int i;
3413
3414 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3415 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3416 *size = _IOC_SIZE(*cmd);
3417 *cmd = ioctl_table[i];
3418 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003419 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 return -EFAULT;
3421 }
3422 return 0;
3423 }
3424 }
3425 return -EINVAL;
3426}
3427
3428static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3429{
3430 if (type)
3431 *g = &floppy_type[type];
3432 else {
3433 LOCK_FDC(drive, 0);
3434 CALL(poll_drive(0, 0));
3435 process_fd_request();
3436 *g = current_type[drive];
3437 }
3438 if (!*g)
3439 return -ENODEV;
3440 return 0;
3441}
3442
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003443static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3444{
3445 int drive = (long)bdev->bd_disk->private_data;
3446 int type = ITYPE(drive_state[drive].fd_device);
3447 struct floppy_struct *g;
3448 int ret;
3449
3450 ret = get_floppy_geometry(drive, type, &g);
3451 if (ret)
3452 return ret;
3453
3454 geo->heads = g->head;
3455 geo->sectors = g->sect;
3456 geo->cylinders = g->track;
3457 return 0;
3458}
3459
Al Viroa4af9b42008-03-02 09:27:55 -05003460static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461 unsigned long param)
3462{
Al Viroa4af9b42008-03-02 09:27:55 -05003463#define FD_IOCTL_ALLOWED (mode & (FMODE_WRITE|FMODE_WRITE_IOCTL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464#define OUT(c,x) case c: outparam = (const char *) (x); break
3465#define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0
3466
Al Viroa4af9b42008-03-02 09:27:55 -05003467 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003468 int type = ITYPE(UDRS->fd_device);
3469 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 int ret;
3471 int size;
3472 union inparam {
3473 struct floppy_struct g; /* geometry */
3474 struct format_descr f;
3475 struct floppy_max_errors max_errors;
3476 struct floppy_drive_params dp;
3477 } inparam; /* parameters coming from user space */
3478 const char *outparam; /* parameters passed back to user space */
3479
3480 /* convert compatibility eject ioctls into floppy eject ioctl.
3481 * We do this in order to provide a means to eject floppy disks before
3482 * installing the new fdutils package */
3483 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003484 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485 DPRINT("obsolete eject ioctl\n");
3486 DPRINT("please use floppycontrol --eject\n");
3487 cmd = FDEJECT;
3488 }
3489
Joe Perchesa81ee542010-03-10 15:20:46 -08003490 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 return -EINVAL;
3492
Joe Perchesa81ee542010-03-10 15:20:46 -08003493 /* convert the old style command into a new style command */
3494 ECALL(normalize_ioctl(&cmd, &size));
3495
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 /* permission checks */
3497 if (((cmd & 0x40) && !FD_IOCTL_ALLOWED) ||
3498 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3499 return -EPERM;
3500
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003501 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3502 return -EINVAL;
3503
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504 /* copyin */
3505 CLEARSTRUCT(&inparam);
3506 if (_IOC_DIR(cmd) & _IOC_WRITE)
3507 ECALL(fd_copyin((void __user *)param, &inparam, size))
3508
3509 switch (cmd) {
3510 case FDEJECT:
3511 if (UDRS->fd_ref != 1)
3512 /* somebody else has this drive open */
3513 return -EBUSY;
3514 LOCK_FDC(drive, 1);
3515
3516 /* do the actual eject. Fails on
3517 * non-Sparc architectures */
3518 ret = fd_eject(UNIT(drive));
3519
3520 USETF(FD_DISK_CHANGED);
3521 USETF(FD_VERIFY);
3522 process_fd_request();
3523 return ret;
3524 case FDCLRPRM:
3525 LOCK_FDC(drive, 1);
3526 current_type[drive] = NULL;
3527 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3528 UDRS->keep_data = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003529 return invalidate_drive(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530 case FDSETPRM:
3531 case FDDEFPRM:
3532 return set_geometry(cmd, &inparam.g,
Al Viroa4af9b42008-03-02 09:27:55 -05003533 drive, type, bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534 case FDGETPRM:
3535 ECALL(get_floppy_geometry(drive, type,
3536 (struct floppy_struct **)
3537 &outparam));
3538 break;
3539
3540 case FDMSGON:
3541 UDP->flags |= FTD_MSG;
3542 return 0;
3543 case FDMSGOFF:
3544 UDP->flags &= ~FTD_MSG;
3545 return 0;
3546
3547 case FDFMTBEG:
3548 LOCK_FDC(drive, 1);
3549 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3550 ret = UDRS->flags;
3551 process_fd_request();
3552 if (ret & FD_VERIFY)
3553 return -ENODEV;
3554 if (!(ret & FD_DISK_WRITABLE))
3555 return -EROFS;
3556 return 0;
3557 case FDFMTTRK:
3558 if (UDRS->fd_ref != 1)
3559 return -EBUSY;
3560 return do_format(drive, &inparam.f);
3561 case FDFMTEND:
3562 case FDFLUSH:
3563 LOCK_FDC(drive, 1);
Al Viroa4af9b42008-03-02 09:27:55 -05003564 return invalidate_drive(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565
3566 case FDSETEMSGTRESH:
3567 UDP->max_errors.reporting =
3568 (unsigned short)(param & 0x0f);
3569 return 0;
3570 OUT(FDGETMAXERRS, &UDP->max_errors);
3571 IN(FDSETMAXERRS, &UDP->max_errors, max_errors);
3572
3573 case FDGETDRVTYP:
3574 outparam = drive_name(type, drive);
3575 SUPBOUND(size, strlen(outparam) + 1);
3576 break;
3577
3578 IN(FDSETDRVPRM, UDP, dp);
3579 OUT(FDGETDRVPRM, UDP);
3580
3581 case FDPOLLDRVSTAT:
3582 LOCK_FDC(drive, 1);
3583 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3584 process_fd_request();
3585 /* fall through */
3586 OUT(FDGETDRVSTAT, UDRS);
3587
3588 case FDRESET:
3589 return user_reset_fdc(drive, (int)param, 1);
3590
3591 OUT(FDGETFDCSTAT, UFDCS);
3592
3593 case FDWERRORCLR:
3594 CLEARSTRUCT(UDRWE);
3595 return 0;
3596 OUT(FDWERRORGET, UDRWE);
3597
3598 case FDRAWCMD:
3599 if (type)
3600 return -EINVAL;
3601 LOCK_FDC(drive, 1);
3602 set_floppy(drive);
3603 CALL(i = raw_cmd_ioctl(cmd, (void __user *)param));
3604 process_fd_request();
3605 return i;
3606
3607 case FDTWADDLE:
3608 LOCK_FDC(drive, 1);
3609 twaddle();
3610 process_fd_request();
3611 return 0;
3612
3613 default:
3614 return -EINVAL;
3615 }
3616
3617 if (_IOC_DIR(cmd) & _IOC_READ)
3618 return fd_copyout((void __user *)param, outparam, size);
3619 else
3620 return 0;
3621#undef OUT
3622#undef IN
3623}
3624
3625static void __init config_types(void)
3626{
Joe Perchesb46df352010-03-10 15:20:46 -08003627 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 int drive;
3629
3630 /* read drive info out of physical CMOS */
3631 drive = 0;
3632 if (!UDP->cmos)
3633 UDP->cmos = FLOPPY0_TYPE;
3634 drive = 1;
3635 if (!UDP->cmos && FLOPPY1_TYPE)
3636 UDP->cmos = FLOPPY1_TYPE;
3637
Jesper Juhl06f748c2007-10-16 23:30:57 -07003638 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639
3640 for (drive = 0; drive < N_DRIVE; drive++) {
3641 unsigned int type = UDP->cmos;
3642 struct floppy_drive_params *params;
3643 const char *name = NULL;
3644 static char temparea[32];
3645
Tobias Klauser945f3902006-01-08 01:05:11 -08003646 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647 params = &default_drive_params[type].params;
3648 if (type) {
3649 name = default_drive_params[type].name;
3650 allowed_drive_mask |= 1 << drive;
3651 } else
3652 allowed_drive_mask &= ~(1 << drive);
3653 } else {
3654 params = &default_drive_params[0].params;
3655 sprintf(temparea, "unknown type %d (usb?)", type);
3656 name = temparea;
3657 }
3658 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003659 const char *prepend;
3660 if (!has_drive) {
3661 prepend = "";
3662 has_drive = true;
3663 pr_info("Floppy drive(s):");
3664 } else {
3665 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 }
Joe Perchesb46df352010-03-10 15:20:46 -08003667
3668 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 }
3670 *UDP = *params;
3671 }
Joe Perchesb46df352010-03-10 15:20:46 -08003672
3673 if (has_drive)
3674 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675}
3676
Al Viroa4af9b42008-03-02 09:27:55 -05003677static int floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678{
Al Viroa4af9b42008-03-02 09:27:55 -05003679 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003681 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682 if (UDRS->fd_ref < 0)
3683 UDRS->fd_ref = 0;
3684 else if (!UDRS->fd_ref--) {
3685 DPRINT("floppy_release with fd_ref == 0");
3686 UDRS->fd_ref = 0;
3687 }
3688 if (!UDRS->fd_ref)
3689 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003690 mutex_unlock(&open_lock);
Ingo Molnar3e541a42006-07-03 00:24:23 -07003691
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 return 0;
3693}
3694
3695/*
3696 * floppy_open check for aliasing (/dev/fd0 can be the same as
3697 * /dev/PS0 etc), and disallows simultaneous access to the same
3698 * drive with different device numbers.
3699 */
Al Viroa4af9b42008-03-02 09:27:55 -05003700static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701{
Al Viroa4af9b42008-03-02 09:27:55 -05003702 int drive = (long)bdev->bd_disk->private_data;
3703 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 int try;
3705 int res = -EBUSY;
3706 char *tmp;
3707
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003708 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003710 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 goto out2;
3712
3713 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
3714 USETF(FD_DISK_CHANGED);
3715 USETF(FD_VERIFY);
3716 }
3717
Al Viroa4af9b42008-03-02 09:27:55 -05003718 if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719 goto out2;
3720
Al Viroa4af9b42008-03-02 09:27:55 -05003721 if (mode & FMODE_EXCL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722 UDRS->fd_ref = -1;
3723 else
3724 UDRS->fd_ref++;
3725
Al Viroa4af9b42008-03-02 09:27:55 -05003726 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727
3728 res = -ENXIO;
3729
3730 if (!floppy_track_buffer) {
3731 /* if opening an ED drive, reserve a big buffer,
3732 * else reserve a small one */
3733 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3734 try = 64; /* Only 48 actually useful */
3735 else
3736 try = 32; /* Only 24 actually useful */
3737
3738 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3739 if (!tmp && !floppy_track_buffer) {
3740 try >>= 1; /* buffer only one side */
3741 INFBOUND(try, 16);
3742 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3743 }
Joe Perchesa81ee542010-03-10 15:20:46 -08003744 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746 if (!tmp && !floppy_track_buffer) {
3747 DPRINT("Unable to allocate DMA memory\n");
3748 goto out;
3749 }
3750 if (floppy_track_buffer) {
3751 if (tmp)
3752 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3753 } else {
3754 buffer_min = buffer_max = -1;
3755 floppy_track_buffer = tmp;
3756 max_buffer_sectors = try;
3757 }
3758 }
3759
Al Viroa4af9b42008-03-02 09:27:55 -05003760 new_dev = MINOR(bdev->bd_dev);
3761 UDRS->fd_device = new_dev;
3762 set_capacity(disks[drive], floppy_sizes[new_dev]);
3763 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764 if (buffer_drive == drive)
3765 buffer_track = -1;
3766 }
3767
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 if (UFDCS->rawcmd == 1)
3769 UFDCS->rawcmd = 2;
3770
Al Viroa4af9b42008-03-02 09:27:55 -05003771 if (!(mode & FMODE_NDELAY)) {
3772 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773 UDRS->last_checked = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003774 check_disk_change(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 if (UTESTF(FD_DISK_CHANGED))
3776 goto out;
3777 }
3778 res = -EROFS;
Al Viroa4af9b42008-03-02 09:27:55 -05003779 if ((mode & FMODE_WRITE) && !(UTESTF(FD_DISK_WRITABLE)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780 goto out;
3781 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003782 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783 return 0;
3784out:
3785 if (UDRS->fd_ref < 0)
3786 UDRS->fd_ref = 0;
3787 else
3788 UDRS->fd_ref--;
3789 if (!UDRS->fd_ref)
3790 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003792 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793 return res;
3794}
3795
3796/*
3797 * Check if the disk has been changed or if a change has been faked.
3798 */
3799static int check_floppy_change(struct gendisk *disk)
3800{
3801 int drive = (long)disk->private_data;
3802
3803 if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY))
3804 return 1;
3805
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003806 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003807 lock_fdc(drive, 0);
3808 poll_drive(0, 0);
3809 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810 }
3811
3812 if (UTESTF(FD_DISK_CHANGED) ||
3813 UTESTF(FD_VERIFY) ||
3814 test_bit(drive, &fake_change) ||
3815 (!ITYPE(UDRS->fd_device) && !current_type[drive]))
3816 return 1;
3817 return 0;
3818}
3819
3820/*
3821 * This implements "read block 0" for floppy_revalidate().
3822 * Needed for format autodetection, checking whether there is
3823 * a disk in the drive, and whether that disk is writable.
3824 */
3825
NeilBrown6712ecf2007-09-27 12:47:43 +02003826static void floppy_rb0_complete(struct bio *bio,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003827 int err)
3828{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 complete((struct completion *)bio->bi_private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830}
3831
3832static int __floppy_read_block_0(struct block_device *bdev)
3833{
3834 struct bio bio;
3835 struct bio_vec bio_vec;
3836 struct completion complete;
3837 struct page *page;
3838 size_t size;
3839
3840 page = alloc_page(GFP_NOIO);
3841 if (!page) {
3842 process_fd_request();
3843 return -ENOMEM;
3844 }
3845
3846 size = bdev->bd_block_size;
3847 if (!size)
3848 size = 1024;
3849
3850 bio_init(&bio);
3851 bio.bi_io_vec = &bio_vec;
3852 bio_vec.bv_page = page;
3853 bio_vec.bv_len = size;
3854 bio_vec.bv_offset = 0;
3855 bio.bi_vcnt = 1;
3856 bio.bi_idx = 0;
3857 bio.bi_size = size;
3858 bio.bi_bdev = bdev;
3859 bio.bi_sector = 0;
3860 init_completion(&complete);
3861 bio.bi_private = &complete;
3862 bio.bi_end_io = floppy_rb0_complete;
3863
3864 submit_bio(READ, &bio);
3865 generic_unplug_device(bdev_get_queue(bdev));
3866 process_fd_request();
3867 wait_for_completion(&complete);
3868
3869 __free_page(page);
3870
3871 return 0;
3872}
3873
3874/* revalidate the floppy disk, i.e. trigger format autodetection by reading
3875 * the bootblock (block 0). "Autodetection" is also needed to check whether
3876 * there is a disk in the drive at all... Thus we also do it for fixed
3877 * geometry formats */
3878static int floppy_revalidate(struct gendisk *disk)
3879{
3880 int drive = (long)disk->private_data;
3881#define NO_GEOM (!current_type[drive] && !ITYPE(UDRS->fd_device))
3882 int cf;
3883 int res = 0;
3884
3885 if (UTESTF(FD_DISK_CHANGED) ||
3886 UTESTF(FD_VERIFY) || test_bit(drive, &fake_change) || NO_GEOM) {
3887 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08003888 pr_info("VFS: revalidate called on non-open device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889 return -EFAULT;
3890 }
3891 lock_fdc(drive, 0);
3892 cf = UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY);
3893 if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)) {
3894 process_fd_request(); /*already done by another thread */
3895 return 0;
3896 }
3897 UDRS->maxblock = 0;
3898 UDRS->maxtrack = 0;
3899 if (buffer_drive == drive)
3900 buffer_track = -1;
3901 clear_bit(drive, &fake_change);
3902 UCLEARF(FD_DISK_CHANGED);
3903 if (cf)
3904 UDRS->generation++;
3905 if (NO_GEOM) {
3906 /* auto-sensing */
3907 res = __floppy_read_block_0(opened_bdev[drive]);
3908 } else {
3909 if (cf)
3910 poll_drive(0, FD_RAW_NEED_DISK);
3911 process_fd_request();
3912 }
3913 }
3914 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
3915 return res;
3916}
3917
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07003918static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07003919 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05003920 .open = floppy_open,
3921 .release = floppy_release,
3922 .locked_ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003923 .getgeo = fd_getgeo,
3924 .media_changed = check_floppy_change,
3925 .revalidate_disk = floppy_revalidate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928/*
3929 * Floppy Driver initialization
3930 * =============================
3931 */
3932
3933/* Determine the floppy disk controller type */
3934/* This routine was written by David C. Niemi */
3935static char __init get_fdc_version(void)
3936{
3937 int r;
3938
3939 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
3940 if (FDCS->reset)
3941 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003942 r = result();
3943 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944 return FDC_NONE; /* No FDC present ??? */
3945 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003946 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3948 }
3949 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003950 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3951 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952 return FDC_UNKNOWN;
3953 }
3954
3955 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003956 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3958 }
3959
3960 output_byte(FD_PERPENDICULAR);
3961 if (need_more_output() == MORE_OUTPUT) {
3962 output_byte(0);
3963 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003964 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965 return FDC_82072A; /* 82072A as found on Sparcs. */
3966 }
3967
3968 output_byte(FD_UNLOCK);
3969 r = result();
3970 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003971 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003972 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973 * LOCK/UNLOCK */
3974 }
3975 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003976 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3977 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 return FDC_UNKNOWN;
3979 }
3980 output_byte(FD_PARTID);
3981 r = result();
3982 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003983 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3984 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985 return FDC_UNKNOWN;
3986 }
3987 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003988 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 return FDC_82077; /* Revised 82077AA passes all the tests */
3990 }
3991 switch (reply_buffer[0] >> 5) {
3992 case 0x0:
3993 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08003994 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995 return FDC_82078;
3996 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08003997 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 return FDC_82078;
3999 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08004000 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001 return FDC_S82078B;
4002 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08004003 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 return FDC_87306;
4005 default:
Joe Perchesb46df352010-03-10 15:20:46 -08004006 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
4007 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 return FDC_82078_UNKN;
4009 }
4010} /* get_fdc_version */
4011
4012/* lilo configuration */
4013
4014static void __init floppy_set_flags(int *ints, int param, int param2)
4015{
4016 int i;
4017
4018 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4019 if (param)
4020 default_drive_params[i].params.flags |= param2;
4021 else
4022 default_drive_params[i].params.flags &= ~param2;
4023 }
4024 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
4025}
4026
4027static void __init daring(int *ints, int param, int param2)
4028{
4029 int i;
4030
4031 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4032 if (param) {
4033 default_drive_params[i].params.select_delay = 0;
4034 default_drive_params[i].params.flags |=
4035 FD_SILENT_DCL_CLEAR;
4036 } else {
4037 default_drive_params[i].params.select_delay =
4038 2 * HZ / 100;
4039 default_drive_params[i].params.flags &=
4040 ~FD_SILENT_DCL_CLEAR;
4041 }
4042 }
4043 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
4044}
4045
4046static void __init set_cmos(int *ints, int dummy, int dummy2)
4047{
4048 int current_drive = 0;
4049
4050 if (ints[0] != 2) {
4051 DPRINT("wrong number of parameters for CMOS\n");
4052 return;
4053 }
4054 current_drive = ints[1];
4055 if (current_drive < 0 || current_drive >= 8) {
4056 DPRINT("bad drive for set_cmos\n");
4057 return;
4058 }
4059#if N_FDC > 1
4060 if (current_drive >= 4 && !FDC2)
4061 FDC2 = 0x370;
4062#endif
4063 DP->cmos = ints[2];
4064 DPRINT("setting CMOS code to %d\n", ints[2]);
4065}
4066
4067static struct param_table {
4068 const char *name;
4069 void (*fn) (int *ints, int param, int param2);
4070 int *var;
4071 int def_param;
4072 int param2;
4073} config_params[] __initdata = {
4074 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4075 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4076 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4077 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4078 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4079 {"daring", daring, NULL, 1, 0},
4080#if N_FDC > 1
4081 {"two_fdc", NULL, &FDC2, 0x370, 0},
4082 {"one_fdc", NULL, &FDC2, 0, 0},
4083#endif
4084 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4085 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4086 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4087 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4088 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4089 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4090 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4091 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4092 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4093 {"nofifo", NULL, &no_fifo, 0x20, 0},
4094 {"usefifo", NULL, &no_fifo, 0, 0},
4095 {"cmos", set_cmos, NULL, 0, 0},
4096 {"slow", NULL, &slow_floppy, 1, 0},
4097 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4098 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4099 {"L40SX", NULL, &print_unex, 0, 0}
4100
4101 EXTRA_FLOPPY_PARAMS
4102};
4103
4104static int __init floppy_setup(char *str)
4105{
4106 int i;
4107 int param;
4108 int ints[11];
4109
4110 str = get_options(str, ARRAY_SIZE(ints), ints);
4111 if (str) {
4112 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4113 if (strcmp(str, config_params[i].name) == 0) {
4114 if (ints[0])
4115 param = ints[1];
4116 else
4117 param = config_params[i].def_param;
4118 if (config_params[i].fn)
4119 config_params[i].
4120 fn(ints, param,
4121 config_params[i].param2);
4122 if (config_params[i].var) {
4123 DPRINT("%s=%d\n", str, param);
4124 *config_params[i].var = param;
4125 }
4126 return 1;
4127 }
4128 }
4129 }
4130 if (str) {
4131 DPRINT("unknown floppy option [%s]\n", str);
4132
4133 DPRINT("allowed options are:");
4134 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004135 pr_cont(" %s", config_params[i].name);
4136 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137 } else
4138 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004139 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140 return 0;
4141}
4142
4143static int have_no_fdc = -ENODEV;
4144
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004145static ssize_t floppy_cmos_show(struct device *dev,
4146 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004147{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004148 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004149 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004150
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004151 drive = p->id;
4152 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004153}
Joe Perches48c8cee2010-03-10 15:20:45 -08004154
4155DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004156
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157static void floppy_device_release(struct device *dev)
4158{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159}
4160
Frans Popc90cd332009-07-25 22:24:54 +02004161static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004162{
4163 int fdc;
4164
4165 for (fdc = 0; fdc < N_FDC; fdc++)
4166 if (FDCS->address != -1)
4167 user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
4168
4169 return 0;
4170}
4171
Alexey Dobriyan47145212009-12-14 18:00:08 -08004172static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004173 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004174 .restore = floppy_resume,
4175};
4176
4177static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004178 .driver = {
4179 .name = "floppy",
Frans Popc90cd332009-07-25 22:24:54 +02004180 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004181 },
4182};
4183
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004184static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185
4186static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4187{
4188 int drive = (*part & 3) | ((*part & 0x80) >> 5);
4189 if (drive >= N_DRIVE ||
4190 !(allowed_drive_mask & (1 << drive)) ||
4191 fdc_state[FDC(drive)].version == FDC_NONE)
4192 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004193 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194 return NULL;
4195 *part = 0;
4196 return get_disk(disks[drive]);
4197}
4198
4199static int __init floppy_init(void)
4200{
4201 int i, unit, drive;
4202 int err, dr;
4203
Kumar Gala68e1ee62008-09-22 14:41:31 -07004204#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004205 if (check_legacy_ioport(FDC1))
4206 return -ENODEV;
4207#endif
4208
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209 raw_cmd = NULL;
4210
4211 for (dr = 0; dr < N_DRIVE; dr++) {
4212 disks[dr] = alloc_disk(1);
4213 if (!disks[dr]) {
4214 err = -ENOMEM;
4215 goto out_put_disk;
4216 }
4217
4218 disks[dr]->major = FLOPPY_MAJOR;
4219 disks[dr]->first_minor = TOMINOR(dr);
4220 disks[dr]->fops = &floppy_fops;
4221 sprintf(disks[dr]->disk_name, "fd%d", dr);
4222
4223 init_timer(&motor_off_timer[dr]);
4224 motor_off_timer[dr].data = dr;
4225 motor_off_timer[dr].function = motor_off_callback;
4226 }
4227
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228 err = register_blkdev(FLOPPY_MAJOR, "fd");
4229 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004230 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004232 err = platform_driver_register(&floppy_driver);
4233 if (err)
4234 goto out_unreg_blkdev;
4235
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236 floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
4237 if (!floppy_queue) {
4238 err = -ENOMEM;
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004239 goto out_unreg_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 }
Martin K. Petersen086fa5f2010-02-26 00:20:38 -05004241 blk_queue_max_hw_sectors(floppy_queue, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242
4243 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4244 floppy_find, NULL, NULL);
4245
4246 for (i = 0; i < 256; i++)
4247 if (ITYPE(i))
4248 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4249 else
4250 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4251
4252 reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
4253 config_types();
4254
4255 for (i = 0; i < N_FDC; i++) {
4256 fdc = i;
4257 CLEARSTRUCT(FDCS);
4258 FDCS->dtr = -1;
4259 FDCS->dor = 0x4;
4260#if defined(__sparc__) || defined(__mc68000__)
4261 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
4262#ifdef __mc68000__
4263 if (MACH_IS_SUN3X)
4264#endif
4265 FDCS->version = FDC_82072A;
4266#endif
4267 }
4268
4269 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 fdc_state[0].address = FDC1;
4271 if (fdc_state[0].address == -1) {
4272 del_timer(&fd_timeout);
4273 err = -ENODEV;
4274 goto out_unreg_region;
4275 }
4276#if N_FDC > 1
4277 fdc_state[1].address = FDC2;
4278#endif
4279
4280 fdc = 0; /* reset fdc in case of unexpected interrupt */
4281 err = floppy_grab_irq_and_dma();
4282 if (err) {
4283 del_timer(&fd_timeout);
4284 err = -EBUSY;
4285 goto out_unreg_region;
4286 }
4287
4288 /* initialise drive state */
4289 for (drive = 0; drive < N_DRIVE; drive++) {
4290 CLEARSTRUCT(UDRS);
4291 CLEARSTRUCT(UDRWE);
4292 USETF(FD_DISK_NEWCHANGE);
4293 USETF(FD_DISK_CHANGED);
4294 USETF(FD_VERIFY);
4295 UDRS->fd_device = -1;
4296 floppy_track_buffer = NULL;
4297 max_buffer_sectors = 0;
4298 }
4299 /*
4300 * Small 10 msec delay to let through any interrupt that
4301 * initialization might have triggered, to not
4302 * confuse detection:
4303 */
4304 msleep(10);
4305
4306 for (i = 0; i < N_FDC; i++) {
4307 fdc = i;
4308 FDCS->driver_version = FD_DRIVER_VERSION;
4309 for (unit = 0; unit < 4; unit++)
4310 FDCS->track[unit] = 0;
4311 if (FDCS->address == -1)
4312 continue;
4313 FDCS->rawcmd = 2;
4314 if (user_reset_fdc(-1, FD_RESET_ALWAYS, 0)) {
4315 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004316 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317 FDCS->address = -1;
4318 FDCS->version = FDC_NONE;
4319 continue;
4320 }
4321 /* Try to determine the floppy controller type */
4322 FDCS->version = get_fdc_version();
4323 if (FDCS->version == FDC_NONE) {
4324 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004325 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326 FDCS->address = -1;
4327 continue;
4328 }
4329 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4330 can_use_virtual_dma = 0;
4331
4332 have_no_fdc = 0;
4333 /* Not all FDCs seem to be able to handle the version command
4334 * properly, so force a reset for the standard FDC clones,
4335 * to avoid interrupt garbage.
4336 */
4337 user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
4338 }
4339 fdc = 0;
4340 del_timer(&fd_timeout);
4341 current_drive = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342 initialising = 0;
4343 if (have_no_fdc) {
4344 DPRINT("no floppy controllers found\n");
4345 err = have_no_fdc;
4346 goto out_flush_work;
4347 }
4348
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 for (drive = 0; drive < N_DRIVE; drive++) {
4350 if (!(allowed_drive_mask & (1 << drive)))
4351 continue;
4352 if (fdc_state[FDC(drive)].version == FDC_NONE)
4353 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004354
4355 floppy_device[drive].name = floppy_device_name;
4356 floppy_device[drive].id = drive;
4357 floppy_device[drive].dev.release = floppy_device_release;
4358
4359 err = platform_device_register(&floppy_device[drive]);
4360 if (err)
4361 goto out_flush_work;
4362
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004363 err = device_create_file(&floppy_device[drive].dev,
4364 &dev_attr_cmos);
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004365 if (err)
4366 goto out_unreg_platform_dev;
4367
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 /* to be cleaned up... */
4369 disks[drive]->private_data = (void *)(long)drive;
4370 disks[drive]->queue = floppy_queue;
4371 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004372 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373 add_disk(disks[drive]);
4374 }
4375
4376 return 0;
4377
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004378out_unreg_platform_dev:
4379 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380out_flush_work:
4381 flush_scheduled_work();
4382 if (usage_count)
4383 floppy_release_irq_and_dma();
4384out_unreg_region:
4385 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4386 blk_cleanup_queue(floppy_queue);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004387out_unreg_driver:
4388 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389out_unreg_blkdev:
4390 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391out_put_disk:
4392 while (dr--) {
4393 del_timer(&motor_off_timer[dr]);
4394 put_disk(disks[dr]);
4395 }
4396 return err;
4397}
4398
4399static DEFINE_SPINLOCK(floppy_usage_lock);
4400
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004401static const struct io_region {
4402 int offset;
4403 int size;
4404} io_regions[] = {
4405 { 2, 1 },
4406 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4407 { 4, 2 },
4408 /* address + 6 is reserved, and may be taken by IDE.
4409 * Unfortunately, Adaptec doesn't know this :-(, */
4410 { 7, 1 },
4411};
4412
4413static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4414{
4415 while (p != io_regions) {
4416 p--;
4417 release_region(FDCS->address + p->offset, p->size);
4418 }
4419}
4420
4421#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4422
4423static int floppy_request_regions(int fdc)
4424{
4425 const struct io_region *p;
4426
4427 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
4428 if (!request_region(FDCS->address + p->offset, p->size, "floppy")) {
4429 DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address + p->offset);
4430 floppy_release_allocated_regions(fdc, p);
4431 return -EBUSY;
4432 }
4433 }
4434 return 0;
4435}
4436
4437static void floppy_release_regions(int fdc)
4438{
4439 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4440}
4441
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442static int floppy_grab_irq_and_dma(void)
4443{
4444 unsigned long flags;
4445
4446 spin_lock_irqsave(&floppy_usage_lock, flags);
4447 if (usage_count++) {
4448 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4449 return 0;
4450 }
4451 spin_unlock_irqrestore(&floppy_usage_lock, flags);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004452
4453 /*
4454 * We might have scheduled a free_irq(), wait it to
4455 * drain first:
4456 */
4457 flush_scheduled_work();
4458
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459 if (fd_request_irq()) {
4460 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4461 FLOPPY_IRQ);
4462 spin_lock_irqsave(&floppy_usage_lock, flags);
4463 usage_count--;
4464 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4465 return -1;
4466 }
4467 if (fd_request_dma()) {
4468 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4469 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004470 if (can_use_virtual_dma & 2)
4471 use_virtual_dma = can_use_virtual_dma = 1;
4472 if (!(can_use_virtual_dma & 1)) {
4473 fd_free_irq();
4474 spin_lock_irqsave(&floppy_usage_lock, flags);
4475 usage_count--;
4476 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4477 return -1;
4478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479 }
4480
4481 for (fdc = 0; fdc < N_FDC; fdc++) {
4482 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004483 if (floppy_request_regions(fdc))
4484 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 }
4486 }
4487 for (fdc = 0; fdc < N_FDC; fdc++) {
4488 if (FDCS->address != -1) {
4489 reset_fdc_info(1);
4490 fd_outb(FDCS->dor, FD_DOR);
4491 }
4492 }
4493 fdc = 0;
4494 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4495
4496 for (fdc = 0; fdc < N_FDC; fdc++)
4497 if (FDCS->address != -1)
4498 fd_outb(FDCS->dor, FD_DOR);
4499 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004500 * The driver will try and free resources and relies on us
4501 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 */
4503 fdc = 0;
4504 irqdma_allocated = 1;
4505 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004506cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507 fd_free_irq();
4508 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004509 while (--fdc >= 0)
4510 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511 spin_lock_irqsave(&floppy_usage_lock, flags);
4512 usage_count--;
4513 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4514 return -1;
4515}
4516
4517static void floppy_release_irq_and_dma(void)
4518{
4519 int old_fdc;
4520#ifdef FLOPPY_SANITY_CHECK
4521#ifndef __sparc__
4522 int drive;
4523#endif
4524#endif
4525 long tmpsize;
4526 unsigned long tmpaddr;
4527 unsigned long flags;
4528
4529 spin_lock_irqsave(&floppy_usage_lock, flags);
4530 if (--usage_count) {
4531 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4532 return;
4533 }
4534 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4535 if (irqdma_allocated) {
4536 fd_disable_dma();
4537 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004538 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539 irqdma_allocated = 0;
4540 }
4541 set_dor(0, ~0, 8);
4542#if N_FDC > 1
4543 set_dor(1, ~8, 0);
4544#endif
4545 floppy_enable_hlt();
4546
4547 if (floppy_track_buffer && max_buffer_sectors) {
4548 tmpsize = max_buffer_sectors * 1024;
4549 tmpaddr = (unsigned long)floppy_track_buffer;
4550 floppy_track_buffer = NULL;
4551 max_buffer_sectors = 0;
4552 buffer_min = buffer_max = -1;
4553 fd_dma_mem_free(tmpaddr, tmpsize);
4554 }
4555#ifdef FLOPPY_SANITY_CHECK
4556#ifndef __sparc__
4557 for (drive = 0; drive < N_FDC * 4; drive++)
4558 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004559 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560#endif
4561
4562 if (timer_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004563 pr_info("floppy timer still active:%s\n", timeout_message);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004565 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004566 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004567 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568#endif
4569 old_fdc = fdc;
4570 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004571 if (FDCS->address != -1)
4572 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573 fdc = old_fdc;
4574}
4575
4576#ifdef MODULE
4577
4578static char *floppy;
4579
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580static void __init parse_floppy_cfg_string(char *cfg)
4581{
4582 char *ptr;
4583
4584 while (*cfg) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004585 for (ptr = cfg; *cfg && *cfg != ' ' && *cfg != '\t'; cfg++)
4586 ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004587 if (*cfg) {
4588 *cfg = '\0';
4589 cfg++;
4590 }
4591 if (*ptr)
4592 floppy_setup(ptr);
4593 }
4594}
4595
Jon Schindler7afea3b2008-04-29 00:59:21 -07004596static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597{
4598 if (floppy)
4599 parse_floppy_cfg_string(floppy);
4600 return floppy_init();
4601}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004602module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603
Jon Schindler7afea3b2008-04-29 00:59:21 -07004604static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605{
4606 int drive;
4607
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4609 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004610 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611
4612 for (drive = 0; drive < N_DRIVE; drive++) {
4613 del_timer_sync(&motor_off_timer[drive]);
4614
4615 if ((allowed_drive_mask & (1 << drive)) &&
4616 fdc_state[FDC(drive)].version != FDC_NONE) {
4617 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004618 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4619 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 }
4621 put_disk(disks[drive]);
4622 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623
4624 del_timer_sync(&fd_timeout);
4625 del_timer_sync(&fd_timer);
4626 blk_cleanup_queue(floppy_queue);
4627
4628 if (usage_count)
4629 floppy_release_irq_and_dma();
4630
4631 /* eject disk, if any */
4632 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633}
Joe Perches48c8cee2010-03-10 15:20:45 -08004634
Jon Schindler7afea3b2008-04-29 00:59:21 -07004635module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636
4637module_param(floppy, charp, 0);
4638module_param(FLOPPY_IRQ, int, 0);
4639module_param(FLOPPY_DMA, int, 0);
4640MODULE_AUTHOR("Alain L. Knaff");
4641MODULE_SUPPORTED_DEVICE("fd");
4642MODULE_LICENSE("GPL");
4643
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004644/* This doesn't actually get used other than for module information */
4645static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004646 {"PNP0700", 0},
4647 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004648};
Joe Perches48c8cee2010-03-10 15:20:45 -08004649
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004650MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4651
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652#else
4653
4654__setup("floppy=", floppy_setup);
4655module_init(floppy_init)
4656#endif
4657
4658MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);