blob: 41f36632719337b880fc14ac5aab3541d6a50133 [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
Joe Perches87f530d2010-03-10 15:20:54 -0800155#ifdef DCL_DEBUG
156#define debug_dcl(test, fmt, args...) \
157 do { if ((test) & FD_DEBUG) DPRINT(fmt, ##args); } while (0)
158#else
159#define debug_dcl(test, fmt, args...) \
160 do { if (0) DPRINT(fmt, ##args); } while (0)
161#endif
162
163
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164/* do print messages for unexpected interrupts */
165static int print_unex = 1;
166#include <linux/module.h>
167#include <linux/sched.h>
168#include <linux/fs.h>
169#include <linux/kernel.h>
170#include <linux/timer.h>
171#include <linux/workqueue.h>
172#define FDPATCHES
173#include <linux/fdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174#include <linux/fd.h>
175#include <linux/hdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176#include <linux/errno.h>
177#include <linux/slab.h>
178#include <linux/mm.h>
179#include <linux/bio.h>
180#include <linux/string.h>
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800181#include <linux/jiffies.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182#include <linux/fcntl.h>
183#include <linux/delay.h>
184#include <linux/mc146818rtc.h> /* CMOS defines */
185#include <linux/ioport.h>
186#include <linux/interrupt.h>
187#include <linux/init.h>
Russell Kingd052d1b2005-10-29 19:07:23 +0100188#include <linux/platform_device.h>
Scott James Remnant83f9ef42009-04-02 16:56:47 -0700189#include <linux/mod_devicetable.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190#include <linux/buffer_head.h> /* for invalidate_buffers() */
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800191#include <linux/mutex.h>
Joe Perchesd4937542010-03-10 15:20:44 -0800192#include <linux/io.h>
193#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195/*
196 * PS/2 floppies have much slower step rates than regular floppies.
197 * It's been recommended that take about 1/4 of the default speed
198 * in some more extreme cases.
199 */
200static int slow_floppy;
201
202#include <asm/dma.h>
203#include <asm/irq.h>
204#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
206static int FLOPPY_IRQ = 6;
207static int FLOPPY_DMA = 2;
208static int can_use_virtual_dma = 2;
209/* =======
210 * can use virtual DMA:
211 * 0 = use of virtual DMA disallowed by config
212 * 1 = use of virtual DMA prescribed by config
213 * 2 = no virtual DMA preference configured. By default try hard DMA,
214 * but fall back on virtual DMA when not enough memory available
215 */
216
217static int use_virtual_dma;
218/* =======
219 * use virtual DMA
220 * 0 using hard DMA
221 * 1 using virtual DMA
222 * This variable is set to virtual when a DMA mem problem arises, and
223 * reset back in floppy_grab_irq_and_dma.
224 * It is not safe to reset it in other circumstances, because the floppy
225 * driver may have several buffers in use at once, and we do currently not
226 * record each buffers capabilities
227 */
228
229static DEFINE_SPINLOCK(floppy_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
231static unsigned short virtual_dma_port = 0x3f0;
David Howells7d12e782006-10-05 14:55:46 +0100232irqreturn_t floppy_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233static int set_dor(int fdc, char mask, char data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
235#define K_64 0x10000 /* 64KB */
236
237/* the following is the mask of allowed drives. By default units 2 and
238 * 3 of both floppy controllers are disabled, because switching on the
239 * motor of these drives causes system hangs on some PCI computers. drive
240 * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
241 * a drive is allowed.
242 *
243 * NOTE: This must come before we include the arch floppy header because
244 * some ports reference this variable from there. -DaveM
245 */
246
247static int allowed_drive_mask = 0x33;
248
249#include <asm/floppy.h>
250
251static int irqdma_allocated;
252
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253#define DEVICE_NAME "floppy"
254
255#include <linux/blkdev.h>
256#include <linux/blkpg.h>
257#include <linux/cdrom.h> /* for the compatibility eject ioctl */
258#include <linux/completion.h>
259
260static struct request *current_req;
261static struct request_queue *floppy_queue;
Joe Perches48c8cee2010-03-10 15:20:45 -0800262static void do_fd_request(struct request_queue *q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
264#ifndef fd_get_dma_residue
265#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
266#endif
267
268/* Dma Memory related stuff */
269
270#ifndef fd_dma_mem_free
271#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
272#endif
273
274#ifndef fd_dma_mem_alloc
Joe Perches48c8cee2010-03-10 15:20:45 -0800275#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL, get_order(size))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276#endif
277
278static inline void fallback_on_nodma_alloc(char **addr, size_t l)
279{
280#ifdef FLOPPY_CAN_FALLBACK_ON_NODMA
281 if (*addr)
282 return; /* we have the memory */
283 if (can_use_virtual_dma != 2)
284 return; /* no fallback allowed */
Joe Perchesb46df352010-03-10 15:20:46 -0800285 pr_info("DMA memory shortage. Temporarily falling back on virtual DMA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 *addr = (char *)nodma_mem_alloc(l);
287#else
288 return;
289#endif
290}
291
292/* End dma memory related stuff */
293
294static unsigned long fake_change;
295static int initialising = 1;
296
Joe Perches48c8cee2010-03-10 15:20:45 -0800297#define ITYPE(x) (((x) >> 2) & 0x1f)
298#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
299#define UNIT(x) ((x) & 0x03) /* drive on fdc */
300#define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700301 /* reverse mapping from unit and fdc to drive */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
Joe Perches48c8cee2010-03-10 15:20:45 -0800304#define DP (&drive_params[current_drive])
305#define DRS (&drive_state[current_drive])
306#define DRWE (&write_errors[current_drive])
307#define FDCS (&fdc_state[fdc])
308#define CLEARF(x) clear_bit(x##_BIT, &DRS->flags)
309#define SETF(x) set_bit(x##_BIT, &DRS->flags)
310#define TESTF(x) test_bit(x##_BIT, &DRS->flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
Joe Perches48c8cee2010-03-10 15:20:45 -0800312#define UDP (&drive_params[drive])
313#define UDRS (&drive_state[drive])
314#define UDRWE (&write_errors[drive])
315#define UFDCS (&fdc_state[FDC(drive)])
316#define UCLEARF(x) clear_bit(x##_BIT, &UDRS->flags)
317#define USETF(x) set_bit(x##_BIT, &UDRS->flags)
318#define UTESTF(x) test_bit(x##_BIT, &UDRS->flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
Joe Perches48c8cee2010-03-10 15:20:45 -0800320#define DPRINT(format, args...) \
Joe Perchesb46df352010-03-10 15:20:46 -0800321 pr_info(DEVICE_NAME "%d: " format, current_drive, ##args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
Joe Perches48c8cee2010-03-10 15:20:45 -0800323#define PH_HEAD(floppy, head) (((((floppy)->stretch & 2) >> 1) ^ head) << 2)
324#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
325
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326/* read/write */
Joe Perches48c8cee2010-03-10 15:20:45 -0800327#define COMMAND (raw_cmd->cmd[0])
328#define DR_SELECT (raw_cmd->cmd[1])
329#define TRACK (raw_cmd->cmd[2])
330#define HEAD (raw_cmd->cmd[3])
331#define SECTOR (raw_cmd->cmd[4])
332#define SIZECODE (raw_cmd->cmd[5])
333#define SECT_PER_TRACK (raw_cmd->cmd[6])
334#define GAP (raw_cmd->cmd[7])
335#define SIZECODE2 (raw_cmd->cmd[8])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336#define NR_RW 9
337
338/* format */
Joe Perches48c8cee2010-03-10 15:20:45 -0800339#define F_SIZECODE (raw_cmd->cmd[2])
340#define F_SECT_PER_TRACK (raw_cmd->cmd[3])
341#define F_GAP (raw_cmd->cmd[4])
342#define F_FILL (raw_cmd->cmd[5])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343#define NR_F 6
344
345/*
Joe Perches48c8cee2010-03-10 15:20:45 -0800346 * Maximum disk size (in kilobytes).
347 * This default is used whenever the current disk size is unknown.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 * [Now it is rather a minimum]
349 */
350#define MAX_DISK_SIZE 4 /* 3984 */
351
352/*
353 * globals used by 'result()'
354 */
355#define MAX_REPLIES 16
356static unsigned char reply_buffer[MAX_REPLIES];
357static int inr; /* size of reply buffer, when called from interrupt */
Joe Perches48c8cee2010-03-10 15:20:45 -0800358#define ST0 (reply_buffer[0])
359#define ST1 (reply_buffer[1])
360#define ST2 (reply_buffer[2])
361#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
362#define R_TRACK (reply_buffer[3])
363#define R_HEAD (reply_buffer[4])
364#define R_SECTOR (reply_buffer[5])
365#define R_SIZECODE (reply_buffer[6])
366
367#define SEL_DLY (2 * HZ / 100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
369/*
370 * this struct defines the different floppy drive types.
371 */
372static struct {
373 struct floppy_drive_params params;
374 const char *name; /* name printed while booting */
375} default_drive_params[] = {
376/* NOTE: the time values in jiffies should be in msec!
377 CMOS drive type
378 | Maximum data rate supported by drive type
379 | | Head load time, msec
380 | | | Head unload time, msec (not used)
381 | | | | Step rate interval, usec
382 | | | | | Time needed for spinup time (jiffies)
383 | | | | | | Timeout for spinning down (jiffies)
384 | | | | | | | Spindown offset (where disk stops)
385 | | | | | | | | Select delay
386 | | | | | | | | | RPS
387 | | | | | | | | | | Max number of tracks
388 | | | | | | | | | | | Interrupt timeout
389 | | | | | | | | | | | | Max nonintlv. sectors
390 | | | | | | | | | | | | | -Max Errors- flags */
391{{0, 500, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 80, 3*HZ, 20, {3,1,2,0,2}, 0,
392 0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },
393
394{{1, 300, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 40, 3*HZ, 17, {3,1,2,0,2}, 0,
395 0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
396
397{{2, 500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0,
398 0, { 2, 5, 6,23,10,20,12, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/
399
400{{3, 250, 16, 16, 3000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
401 0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/
402
403{{4, 500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
404 0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/
405
406{{5, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
407 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
408
409{{6, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
410 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*/
411/* | --autodetected formats--- | | |
412 * read_track | | Name printed when booting
413 * | Native format
414 * Frequency of disk change checks */
415};
416
417static struct floppy_drive_params drive_params[N_DRIVE];
418static struct floppy_drive_struct drive_state[N_DRIVE];
419static struct floppy_write_errors write_errors[N_DRIVE];
420static struct timer_list motor_off_timer[N_DRIVE];
421static struct gendisk *disks[N_DRIVE];
422static struct block_device *opened_bdev[N_DRIVE];
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800423static DEFINE_MUTEX(open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
425
426/*
427 * This struct defines the different floppy types.
428 *
429 * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
430 * types (e.g. 360kB diskette in 1.2MB drive, etc.). Bit 1 of 'stretch'
431 * tells if the disk is in Commodore 1581 format, which means side 0 sectors
432 * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
433 * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
434 * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
435 * side 0 is on physical side 0 (but with the misnamed sector IDs).
436 * 'stretch' should probably be renamed to something more general, like
Keith Wansbrough9e491842008-09-22 14:57:17 -0700437 * 'options'.
438 *
439 * Bits 2 through 9 of 'stretch' tell the number of the first sector.
440 * The LSB (bit 2) is flipped. For most disks, the first sector
441 * is 1 (represented by 0x00<<2). For some CP/M and music sampler
442 * disks (such as Ensoniq EPS 16plus) it is 0 (represented as 0x01<<2).
443 * For Amstrad CPC disks it is 0xC1 (represented as 0xC0<<2).
444 *
445 * Other parameters should be self-explanatory (see also setfdprm(8)).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 */
447/*
448 Size
449 | Sectors per track
450 | | Head
451 | | | Tracks
452 | | | | Stretch
453 | | | | | Gap 1 size
454 | | | | | | Data rate, | 0x40 for perp
455 | | | | | | | Spec1 (stepping rate, head unload
456 | | | | | | | | /fmt gap (gap2) */
457static struct floppy_struct floppy_type[32] = {
458 { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* 0 no testing */
459 { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360" }, /* 1 360KB PC */
460 { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" }, /* 2 1.2MB AT */
461 { 720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360" }, /* 3 360KB SS 3.5" */
462 { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720" }, /* 4 720KB 3.5" */
463 { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360" }, /* 5 360KB AT */
464 { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" }, /* 6 720KB AT */
465 { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /* 7 1.44MB 3.5" */
466 { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /* 8 2.88MB 3.5" */
467 { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" }, /* 9 3.12MB 3.5" */
468
469 { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */
470 { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */
471 { 820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410" }, /* 12 410KB 5.25" */
472 { 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820" }, /* 13 820KB 3.5" */
473 { 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" }, /* 14 1.48MB 5.25" */
474 { 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" }, /* 15 1.72MB 3.5" */
475 { 840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420" }, /* 16 420KB 5.25" */
476 { 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830" }, /* 17 830KB 3.5" */
477 { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" }, /* 18 1.49MB 5.25" */
478 { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5" */
479
480 { 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880" }, /* 20 880KB 5.25" */
481 { 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5" */
482 { 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5" */
483 { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25" */
484 { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5" */
485 { 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5" */
486 { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5" */
487 { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5" */
488 { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5" */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5" */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700490
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */
492 { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */
493};
494
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495#define SECTSIZE (_FD_SECTSIZE(*floppy))
496
497/* Auto-detection: Disk type used until the next media change occurs. */
498static struct floppy_struct *current_type[N_DRIVE];
499
500/*
501 * User-provided type information. current_type points to
502 * the respective entry of this array.
503 */
504static struct floppy_struct user_params[N_DRIVE];
505
506static sector_t floppy_sizes[256];
507
Hannes Reinecke94fd0db2005-07-15 10:09:25 +0200508static char floppy_device_name[] = "floppy";
509
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510/*
511 * The driver is trying to determine the correct media format
512 * while probing is set. rw_interrupt() clears it after a
513 * successful access.
514 */
515static int probing;
516
517/* Synchronization of FDC access. */
Joe Perches48c8cee2010-03-10 15:20:45 -0800518#define FD_COMMAND_NONE -1
519#define FD_COMMAND_ERROR 2
520#define FD_COMMAND_OKAY 3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
522static volatile int command_status = FD_COMMAND_NONE;
523static unsigned long fdc_busy;
524static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
525static DECLARE_WAIT_QUEUE_HEAD(command_done);
526
527#define NO_SIGNAL (!interruptible || !signal_pending(current))
Joe Perches48c8cee2010-03-10 15:20:45 -0800528#define CALL(x) if ((x) == -EINTR) return -EINTR
529#define ECALL(x) if ((ret = (x))) return ret;
530#define _WAIT(x,i) CALL(ret=wait_til_done((x),i))
531#define WAIT(x) _WAIT((x),interruptible)
532#define IWAIT(x) _WAIT((x),1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
534/* Errors during formatting are counted here. */
535static int format_errors;
536
537/* Format request descriptor. */
538static struct format_descr format_req;
539
540/*
541 * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
542 * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
543 * H is head unload time (1=16ms, 2=32ms, etc)
544 */
545
546/*
547 * Track buffer
548 * Because these are written to by the DMA controller, they must
549 * not contain a 64k byte boundary crossing, or data will be
550 * corrupted/lost.
551 */
552static char *floppy_track_buffer;
553static int max_buffer_sectors;
554
555static int *errors;
Jesper Juhl06f748c2007-10-16 23:30:57 -0700556typedef void (*done_f)(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557static struct cont_t {
Joe Perches48c8cee2010-03-10 15:20:45 -0800558 void (*interrupt)(void);
559 /* this is called after the interrupt of the
560 * main command */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700561 void (*redo)(void); /* this is called to retry the operation */
562 void (*error)(void); /* this is called to tally an error */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 done_f done; /* this is called to say if the operation has
564 * succeeded/failed */
565} *cont;
566
567static void floppy_ready(void);
568static void floppy_start(void);
569static void process_fd_request(void);
570static void recalibrate_floppy(void);
571static void floppy_shutdown(unsigned long);
572
Philippe De Muyter5a74db02009-02-18 14:48:36 -0800573static int floppy_request_regions(int);
574static void floppy_release_regions(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575static int floppy_grab_irq_and_dma(void);
576static void floppy_release_irq_and_dma(void);
577
578/*
579 * The "reset" variable should be tested whenever an interrupt is scheduled,
580 * after the commands have been sent. This is to ensure that the driver doesn't
581 * get wedged when the interrupt doesn't come because of a failed command.
582 * reset doesn't need to be tested before sending commands, because
583 * output_byte is automatically disabled when reset is set.
584 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585static void reset_fdc(void);
586
587/*
588 * These are global variables, as that's the easiest way to give
589 * information to interrupts. They are the data used for the current
590 * request.
591 */
Joe Perches48c8cee2010-03-10 15:20:45 -0800592#define NO_TRACK -1
593#define NEED_1_RECAL -2
594#define NEED_2_RECAL -3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
596static int usage_count;
597
598/* buffer related variables */
599static int buffer_track = -1;
600static int buffer_drive = -1;
601static int buffer_min = -1;
602static int buffer_max = -1;
603
604/* fdc related variables, should end up in a struct */
605static struct floppy_fdc_state fdc_state[N_FDC];
606static int fdc; /* current fdc */
607
608static struct floppy_struct *_floppy = floppy_type;
609static unsigned char current_drive;
610static long current_count_sectors;
611static unsigned char fsector_t; /* sector in track */
612static unsigned char in_sector_offset; /* offset within physical sector,
613 * expressed in units of 512 bytes */
614
615#ifndef fd_eject
616static inline int fd_eject(int drive)
617{
618 return -EINVAL;
619}
620#endif
621
622/*
623 * Debugging
624 * =========
625 */
626#ifdef DEBUGT
627static long unsigned debugtimer;
628
629static inline void set_debugt(void)
630{
631 debugtimer = jiffies;
632}
633
634static inline void debugt(const char *message)
635{
636 if (DP->flags & DEBUGT)
Joe Perchesb46df352010-03-10 15:20:46 -0800637 pr_info("%s dtime=%lu\n", message, jiffies - debugtimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638}
639#else
640static inline void set_debugt(void) { }
641static inline void debugt(const char *message) { }
642#endif /* DEBUGT */
643
Joe Perchesa0a52d62010-03-10 15:20:52 -0800644typedef void (*timeout_fn)(unsigned long);
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700645static DEFINE_TIMER(fd_timeout, floppy_shutdown, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
647static const char *timeout_message;
648
649#ifdef FLOPPY_SANITY_CHECK
650static void is_alive(const char *message)
651{
652 /* this routine checks whether the floppy driver is "alive" */
653 if (test_bit(0, &fdc_busy) && command_status < 2
654 && !timer_pending(&fd_timeout)) {
655 DPRINT("timeout handler died: %s\n", message);
656 }
657}
658#endif
659
Joe Perches48c8cee2010-03-10 15:20:45 -0800660static void (*do_floppy)(void) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661
662#ifdef FLOPPY_SANITY_CHECK
663
664#define OLOGSIZE 20
665
Joe Perches48c8cee2010-03-10 15:20:45 -0800666static void (*lasthandler)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667static unsigned long interruptjiffies;
668static unsigned long resultjiffies;
669static int resultsize;
670static unsigned long lastredo;
671
672static struct output_log {
673 unsigned char data;
674 unsigned char status;
675 unsigned long jiffies;
676} output_log[OLOGSIZE];
677
678static int output_log_pos;
679#endif
680
681#define current_reqD -1
682#define MAXTIMEOUT -2
683
684static void __reschedule_timeout(int drive, const char *message, int marg)
685{
686 if (drive == current_reqD)
687 drive = current_drive;
688 del_timer(&fd_timeout);
Eric Sesterhenn / Snakebyte4acb3e22007-05-23 13:58:15 -0700689 if (drive < 0 || drive >= N_DRIVE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 fd_timeout.expires = jiffies + 20UL * HZ;
691 drive = 0;
692 } else
693 fd_timeout.expires = jiffies + UDP->timeout;
694 add_timer(&fd_timeout);
Joe Perchesa81ee542010-03-10 15:20:46 -0800695 if (UDP->flags & FD_DEBUG)
Joe Perchesb46df352010-03-10 15:20:46 -0800696 DPRINT("reschedule timeout %s %d\n", message, marg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 timeout_message = message;
698}
699
700static void reschedule_timeout(int drive, const char *message, int marg)
701{
702 unsigned long flags;
703
704 spin_lock_irqsave(&floppy_lock, flags);
705 __reschedule_timeout(drive, message, marg);
706 spin_unlock_irqrestore(&floppy_lock, flags);
707}
708
Joe Perches48c8cee2010-03-10 15:20:45 -0800709#define INFBOUND(a, b) (a) = max_t(int, a, b)
710#define SUPBOUND(a, b) (a) = min_t(int, a, b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
712/*
713 * Bottom half floppy driver.
714 * ==========================
715 *
716 * This part of the file contains the code talking directly to the hardware,
717 * and also the main service loop (seek-configure-spinup-command)
718 */
719
720/*
721 * disk change.
722 * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
723 * and the last_checked date.
724 *
725 * last_checked is the date of the last check which showed 'no disk change'
726 * FD_DISK_CHANGE is set under two conditions:
727 * 1. The floppy has been changed after some i/o to that floppy already
728 * took place.
729 * 2. No floppy disk is in the drive. This is done in order to ensure that
730 * requests are quickly flushed in case there is no disk in the drive. It
731 * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
732 * the drive.
733 *
734 * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
735 * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
736 * each seek. If a disk is present, the disk change line should also be
737 * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
738 * change line is set, this means either that no disk is in the drive, or
739 * that it has been removed since the last seek.
740 *
741 * This means that we really have a third possibility too:
742 * The floppy has been changed after the last seek.
743 */
744
745static int disk_change(int drive)
746{
747 int fdc = FDC(drive);
Jesper Juhl06f748c2007-10-16 23:30:57 -0700748
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749#ifdef FLOPPY_SANITY_CHECK
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800750 if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 DPRINT("WARNING disk change called early\n");
752 if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
753 (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
754 DPRINT("probing disk change on unselected drive\n");
755 DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
756 (unsigned int)FDCS->dor);
757 }
758#endif
759
Joe Perches87f530d2010-03-10 15:20:54 -0800760 debug_dcl(UDP->flags,
761 "checking disk change line for drive %d\n", drive);
762 debug_dcl(UDP->flags, "jiffies=%lu\n", jiffies);
763 debug_dcl(UDP->flags, "disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
764 debug_dcl(UDP->flags, "flags=%lx\n", UDRS->flags);
765
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 if (UDP->flags & FD_BROKEN_DCL)
767 return UTESTF(FD_DISK_CHANGED);
768 if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
769 USETF(FD_VERIFY); /* verify write protection */
770 if (UDRS->maxblock) {
771 /* mark it changed */
772 USETF(FD_DISK_CHANGED);
773 }
774
775 /* invalidate its geometry */
776 if (UDRS->keep_data >= 0) {
777 if ((UDP->flags & FTD_MSG) &&
778 current_type[drive] != NULL)
779 DPRINT("Disk type is undefined after "
780 "disk change\n");
781 current_type[drive] = NULL;
782 floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
783 }
784
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 return 1;
786 } else {
787 UDRS->last_checked = jiffies;
788 UCLEARF(FD_DISK_NEWCHANGE);
789 }
790 return 0;
791}
792
793static inline int is_selected(int dor, int unit)
794{
795 return ((dor & (0x10 << unit)) && (dor & 3) == unit);
796}
797
798static int set_dor(int fdc, char mask, char data)
799{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700800 unsigned char unit;
801 unsigned char drive;
802 unsigned char newdor;
803 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
805 if (FDCS->address == -1)
806 return -1;
807
808 olddor = FDCS->dor;
809 newdor = (olddor & mask) | data;
810 if (newdor != olddor) {
811 unit = olddor & 0x3;
812 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
813 drive = REVDRIVE(fdc, unit);
Joe Perches87f530d2010-03-10 15:20:54 -0800814 debug_dcl(UDP->flags,
815 "calling disk change from set_dor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 disk_change(drive);
817 }
818 FDCS->dor = newdor;
819 fd_outb(newdor, FD_DOR);
820
821 unit = newdor & 0x3;
822 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
823 drive = REVDRIVE(fdc, unit);
824 UDRS->select_date = jiffies;
825 }
826 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 return olddor;
828}
829
830static void twaddle(void)
831{
832 if (DP->select_delay)
833 return;
834 fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
835 fd_outb(FDCS->dor, FD_DOR);
836 DRS->select_date = jiffies;
837}
838
839/* reset all driver information about the current fdc. This is needed after
840 * a reset, and after a raw command. */
841static void reset_fdc_info(int mode)
842{
843 int drive;
844
845 FDCS->spec1 = FDCS->spec2 = -1;
846 FDCS->need_configure = 1;
847 FDCS->perp_mode = 1;
848 FDCS->rawcmd = 0;
849 for (drive = 0; drive < N_DRIVE; drive++)
850 if (FDC(drive) == fdc && (mode || UDRS->track != NEED_1_RECAL))
851 UDRS->track = NEED_2_RECAL;
852}
853
854/* selects the fdc and drive, and enables the fdc's input/dma. */
855static void set_fdc(int drive)
856{
857 if (drive >= 0 && drive < N_DRIVE) {
858 fdc = FDC(drive);
859 current_drive = drive;
860 }
861 if (fdc != 1 && fdc != 0) {
Joe Perchesb46df352010-03-10 15:20:46 -0800862 pr_info("bad fdc value\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 return;
864 }
865 set_dor(fdc, ~0, 8);
866#if N_FDC > 1
867 set_dor(1 - fdc, ~8, 0);
868#endif
869 if (FDCS->rawcmd == 2)
870 reset_fdc_info(1);
871 if (fd_inb(FD_STATUS) != STATUS_READY)
872 FDCS->reset = 1;
873}
874
875/* locks the driver */
876static int _lock_fdc(int drive, int interruptible, int line)
877{
878 if (!usage_count) {
Joe Perchesb46df352010-03-10 15:20:46 -0800879 pr_err("Trying to lock fdc while usage count=0 at line %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 line);
881 return -1;
882 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883
884 if (test_and_set_bit(0, &fdc_busy)) {
885 DECLARE_WAITQUEUE(wait, current);
886 add_wait_queue(&fdc_wait, &wait);
887
888 for (;;) {
889 set_current_state(TASK_INTERRUPTIBLE);
890
891 if (!test_and_set_bit(0, &fdc_busy))
892 break;
893
894 schedule();
895
896 if (!NO_SIGNAL) {
897 remove_wait_queue(&fdc_wait, &wait);
898 return -EINTR;
899 }
900 }
901
902 set_current_state(TASK_RUNNING);
903 remove_wait_queue(&fdc_wait, &wait);
Ingo Molnar3e541a42006-07-03 00:24:23 -0700904 flush_scheduled_work();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 }
906 command_status = FD_COMMAND_NONE;
907
908 __reschedule_timeout(drive, "lock fdc", 0);
909 set_fdc(drive);
910 return 0;
911}
912
Joe Perches48c8cee2010-03-10 15:20:45 -0800913#define lock_fdc(drive, interruptible) \
914 _lock_fdc(drive, interruptible, __LINE__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916/* unlocks the driver */
917static inline void unlock_fdc(void)
918{
919 unsigned long flags;
920
921 raw_cmd = NULL;
922 if (!test_bit(0, &fdc_busy))
923 DPRINT("FDC access conflict!\n");
924
925 if (do_floppy)
926 DPRINT("device interrupt still active at FDC release: %p!\n",
927 do_floppy);
928 command_status = FD_COMMAND_NONE;
929 spin_lock_irqsave(&floppy_lock, flags);
930 del_timer(&fd_timeout);
931 cont = NULL;
932 clear_bit(0, &fdc_busy);
Tejun Heo9934c8c2009-05-08 11:54:16 +0900933 if (current_req || blk_peek_request(floppy_queue))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 do_fd_request(floppy_queue);
935 spin_unlock_irqrestore(&floppy_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 wake_up(&fdc_wait);
937}
938
939/* switches the motor off after a given timeout */
940static void motor_off_callback(unsigned long nr)
941{
942 unsigned char mask = ~(0x10 << UNIT(nr));
943
944 set_dor(FDC(nr), mask, 0);
945}
946
947/* schedules motor off */
948static void floppy_off(unsigned int drive)
949{
950 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700951 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
953 if (!(FDCS->dor & (0x10 << UNIT(drive))))
954 return;
955
956 del_timer(motor_off_timer + drive);
957
958 /* make spindle stop in a position which minimizes spinup time
959 * next time */
960 if (UDP->rps) {
961 delta = jiffies - UDRS->first_read_date + HZ -
962 UDP->spindown_offset;
963 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
964 motor_off_timer[drive].expires =
965 jiffies + UDP->spindown - delta;
966 }
967 add_timer(motor_off_timer + drive);
968}
969
970/*
971 * cycle through all N_DRIVE floppy drives, for disk change testing.
972 * stopping at current drive. This is done before any long operation, to
973 * be sure to have up to date disk change information.
974 */
975static void scandrives(void)
976{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700977 int i;
978 int drive;
979 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
981 if (DP->select_delay)
982 return;
983
984 saved_drive = current_drive;
985 for (i = 0; i < N_DRIVE; i++) {
986 drive = (saved_drive + i + 1) % N_DRIVE;
987 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
988 continue; /* skip closed drives */
989 set_fdc(drive);
990 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
991 (0x10 << UNIT(drive))))
992 /* switch the motor off again, if it was off to
993 * begin with */
994 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
995 }
996 set_fdc(saved_drive);
997}
998
999static void empty(void)
1000{
1001}
1002
David Howells65f27f32006-11-22 14:55:48 +00001003static DECLARE_WORK(floppy_work, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004
Joe Perches48c8cee2010-03-10 15:20:45 -08001005static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006{
David Howells65f27f32006-11-22 14:55:48 +00001007 PREPARE_WORK(&floppy_work, (work_func_t)handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 schedule_work(&floppy_work);
1009}
1010
Ingo Molnar8d06afa2005-09-09 13:10:40 -07001011static DEFINE_TIMER(fd_timer, NULL, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012
1013static void cancel_activity(void)
1014{
1015 unsigned long flags;
1016
1017 spin_lock_irqsave(&floppy_lock, flags);
1018 do_floppy = NULL;
David Howells65f27f32006-11-22 14:55:48 +00001019 PREPARE_WORK(&floppy_work, (work_func_t)empty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 del_timer(&fd_timer);
1021 spin_unlock_irqrestore(&floppy_lock, flags);
1022}
1023
1024/* this function makes sure that the disk stays in the drive during the
1025 * transfer */
1026static void fd_watchdog(void)
1027{
Joe Perches87f530d2010-03-10 15:20:54 -08001028 debug_dcl(DP->flags, "calling disk change from watchdog\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
1030 if (disk_change(current_drive)) {
1031 DPRINT("disk removed during i/o\n");
1032 cancel_activity();
1033 cont->done(0);
1034 reset_fdc();
1035 } else {
1036 del_timer(&fd_timer);
Joe Perchesa0a52d62010-03-10 15:20:52 -08001037 fd_timer.function = (timeout_fn)fd_watchdog;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 fd_timer.expires = jiffies + HZ / 10;
1039 add_timer(&fd_timer);
1040 }
1041}
1042
1043static void main_command_interrupt(void)
1044{
1045 del_timer(&fd_timer);
1046 cont->interrupt();
1047}
1048
1049/* waits for a delay (spinup or select) to pass */
1050static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
1051{
1052 if (FDCS->reset) {
1053 reset_fdc(); /* do the reset during sleep to win time
1054 * if we don't need to sleep, it's a good
1055 * occasion anyways */
1056 return 1;
1057 }
1058
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001059 if (time_before(jiffies, delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 del_timer(&fd_timer);
1061 fd_timer.function = function;
1062 fd_timer.expires = delay;
1063 add_timer(&fd_timer);
1064 return 1;
1065 }
1066 return 0;
1067}
1068
1069static DEFINE_SPINLOCK(floppy_hlt_lock);
1070static int hlt_disabled;
1071static void floppy_disable_hlt(void)
1072{
1073 unsigned long flags;
1074
1075 spin_lock_irqsave(&floppy_hlt_lock, flags);
1076 if (!hlt_disabled) {
1077 hlt_disabled = 1;
1078#ifdef HAVE_DISABLE_HLT
1079 disable_hlt();
1080#endif
1081 }
1082 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1083}
1084
1085static void floppy_enable_hlt(void)
1086{
1087 unsigned long flags;
1088
1089 spin_lock_irqsave(&floppy_hlt_lock, flags);
1090 if (hlt_disabled) {
1091 hlt_disabled = 0;
1092#ifdef HAVE_DISABLE_HLT
1093 enable_hlt();
1094#endif
1095 }
1096 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1097}
1098
1099static void setup_DMA(void)
1100{
1101 unsigned long f;
1102
1103#ifdef FLOPPY_SANITY_CHECK
1104 if (raw_cmd->length == 0) {
1105 int i;
1106
Joe Perchesb46df352010-03-10 15:20:46 -08001107 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001109 pr_cont("%x,", raw_cmd->cmd[i]);
1110 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 cont->done(0);
1112 FDCS->reset = 1;
1113 return;
1114 }
1115 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001116 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 cont->done(0);
1118 FDCS->reset = 1;
1119 return;
1120 }
1121#endif
1122 f = claim_dma_lock();
1123 fd_disable_dma();
1124#ifdef fd_dma_setup
1125 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1126 (raw_cmd->flags & FD_RAW_READ) ?
1127 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1128 release_dma_lock(f);
1129 cont->done(0);
1130 FDCS->reset = 1;
1131 return;
1132 }
1133 release_dma_lock(f);
1134#else
1135 fd_clear_dma_ff();
1136 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1137 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1138 DMA_MODE_READ : DMA_MODE_WRITE);
1139 fd_set_dma_addr(raw_cmd->kernel_data);
1140 fd_set_dma_count(raw_cmd->length);
1141 virtual_dma_port = FDCS->address;
1142 fd_enable_dma();
1143 release_dma_lock(f);
1144#endif
1145 floppy_disable_hlt();
1146}
1147
1148static void show_floppy(void);
1149
1150/* waits until the fdc becomes ready */
1151static int wait_til_ready(void)
1152{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001153 int status;
1154 int counter;
1155
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 if (FDCS->reset)
1157 return -1;
1158 for (counter = 0; counter < 10000; counter++) {
1159 status = fd_inb(FD_STATUS);
1160 if (status & STATUS_READY)
1161 return status;
1162 }
1163 if (!initialising) {
1164 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1165 show_floppy();
1166 }
1167 FDCS->reset = 1;
1168 return -1;
1169}
1170
1171/* sends a command byte to the fdc */
1172static int output_byte(char byte)
1173{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001174 int status = wait_til_ready();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001176 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 return -1;
1178 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY) {
1179 fd_outb(byte, FD_DATA);
1180#ifdef FLOPPY_SANITY_CHECK
1181 output_log[output_log_pos].data = byte;
1182 output_log[output_log_pos].status = status;
1183 output_log[output_log_pos].jiffies = jiffies;
1184 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
1185#endif
1186 return 0;
1187 }
1188 FDCS->reset = 1;
1189 if (!initialising) {
1190 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1191 byte, fdc, status);
1192 show_floppy();
1193 }
1194 return -1;
1195}
1196
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197/* gets the response from the fdc */
1198static int result(void)
1199{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001200 int i;
1201 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202
1203 for (i = 0; i < MAX_REPLIES; i++) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001204 status = wait_til_ready();
1205 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 break;
1207 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1208 if ((status & ~STATUS_BUSY) == STATUS_READY) {
1209#ifdef FLOPPY_SANITY_CHECK
1210 resultjiffies = jiffies;
1211 resultsize = i;
1212#endif
1213 return i;
1214 }
1215 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1216 reply_buffer[i] = fd_inb(FD_DATA);
1217 else
1218 break;
1219 }
1220 if (!initialising) {
1221 DPRINT
1222 ("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1223 fdc, status, i);
1224 show_floppy();
1225 }
1226 FDCS->reset = 1;
1227 return -1;
1228}
1229
1230#define MORE_OUTPUT -2
1231/* does the fdc need more output? */
1232static int need_more_output(void)
1233{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001234 int status = wait_til_ready();
Jesper Juhl06f748c2007-10-16 23:30:57 -07001235
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001236 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 return -1;
1238 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY)
1239 return MORE_OUTPUT;
1240 return result();
1241}
1242
1243/* Set perpendicular mode as required, based on data rate, if supported.
1244 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1245 */
1246static inline void perpendicular_mode(void)
1247{
1248 unsigned char perp_mode;
1249
1250 if (raw_cmd->rate & 0x40) {
1251 switch (raw_cmd->rate & 3) {
1252 case 0:
1253 perp_mode = 2;
1254 break;
1255 case 3:
1256 perp_mode = 3;
1257 break;
1258 default:
1259 DPRINT("Invalid data rate for perpendicular mode!\n");
1260 cont->done(0);
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001261 FDCS->reset = 1;
1262 /*
1263 * convenient way to return to
1264 * redo without too much hassle
1265 * (deep stack et al.)
1266 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 return;
1268 }
1269 } else
1270 perp_mode = 0;
1271
1272 if (FDCS->perp_mode == perp_mode)
1273 return;
1274 if (FDCS->version >= FDC_82077_ORIG) {
1275 output_byte(FD_PERPENDICULAR);
1276 output_byte(perp_mode);
1277 FDCS->perp_mode = perp_mode;
1278 } else if (perp_mode) {
1279 DPRINT("perpendicular mode not supported by this FDC.\n");
1280 }
1281} /* perpendicular_mode */
1282
1283static int fifo_depth = 0xa;
1284static int no_fifo;
1285
1286static int fdc_configure(void)
1287{
1288 /* Turn on FIFO */
1289 output_byte(FD_CONFIGURE);
1290 if (need_more_output() != MORE_OUTPUT)
1291 return 0;
1292 output_byte(0);
1293 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1294 output_byte(0); /* pre-compensation from track
1295 0 upwards */
1296 return 1;
1297}
1298
1299#define NOMINAL_DTR 500
1300
1301/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1302 * head load time, and DMA disable flag to values needed by floppy.
1303 *
1304 * The value "dtr" is the data transfer rate in Kbps. It is needed
1305 * to account for the data rate-based scaling done by the 82072 and 82077
1306 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1307 * 8272a).
1308 *
1309 * Note that changing the data transfer rate has a (probably deleterious)
1310 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1311 * fdc_specify is called again after each data transfer rate
1312 * change.
1313 *
1314 * srt: 1000 to 16000 in microseconds
1315 * hut: 16 to 240 milliseconds
1316 * hlt: 2 to 254 milliseconds
1317 *
1318 * These values are rounded up to the next highest available delay time.
1319 */
1320static void fdc_specify(void)
1321{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001322 unsigned char spec1;
1323 unsigned char spec2;
1324 unsigned long srt;
1325 unsigned long hlt;
1326 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 unsigned long dtr = NOMINAL_DTR;
1328 unsigned long scale_dtr = NOMINAL_DTR;
1329 int hlt_max_code = 0x7f;
1330 int hut_max_code = 0xf;
1331
1332 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1333 fdc_configure();
1334 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 }
1336
1337 switch (raw_cmd->rate & 0x03) {
1338 case 3:
1339 dtr = 1000;
1340 break;
1341 case 1:
1342 dtr = 300;
1343 if (FDCS->version >= FDC_82078) {
1344 /* chose the default rate table, not the one
1345 * where 1 = 2 Mbps */
1346 output_byte(FD_DRIVESPEC);
1347 if (need_more_output() == MORE_OUTPUT) {
1348 output_byte(UNIT(current_drive));
1349 output_byte(0xc0);
1350 }
1351 }
1352 break;
1353 case 2:
1354 dtr = 250;
1355 break;
1356 }
1357
1358 if (FDCS->version >= FDC_82072) {
1359 scale_dtr = dtr;
1360 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1361 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1362 }
1363
1364 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001365 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001366 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001368
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 SUPBOUND(srt, 0xf);
1370 INFBOUND(srt, 0);
1371
Julia Lawall061837b2008-09-22 14:57:16 -07001372 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 if (hlt < 0x01)
1374 hlt = 0x01;
1375 else if (hlt > 0x7f)
1376 hlt = hlt_max_code;
1377
Julia Lawall061837b2008-09-22 14:57:16 -07001378 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 if (hut < 0x1)
1380 hut = 0x1;
1381 else if (hut > 0xf)
1382 hut = hut_max_code;
1383
1384 spec1 = (srt << 4) | hut;
1385 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1386
1387 /* If these parameters did not change, just return with success */
1388 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1389 /* Go ahead and set spec1 and spec2 */
1390 output_byte(FD_SPECIFY);
1391 output_byte(FDCS->spec1 = spec1);
1392 output_byte(FDCS->spec2 = spec2);
1393 }
1394} /* fdc_specify */
1395
1396/* Set the FDC's data transfer rate on behalf of the specified drive.
1397 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1398 * of the specify command (i.e. using the fdc_specify function).
1399 */
1400static int fdc_dtr(void)
1401{
1402 /* If data rate not already set to desired value, set it. */
1403 if ((raw_cmd->rate & 3) == FDCS->dtr)
1404 return 0;
1405
1406 /* Set dtr */
1407 fd_outb(raw_cmd->rate & 3, FD_DCR);
1408
1409 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1410 * need a stabilization period of several milliseconds to be
1411 * enforced after data rate changes before R/W operations.
1412 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1413 */
1414 FDCS->dtr = raw_cmd->rate & 3;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001415 return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
1416 (timeout_fn)floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417} /* fdc_dtr */
1418
1419static void tell_sector(void)
1420{
Joe Perchesb46df352010-03-10 15:20:46 -08001421 pr_cont(": track %d, head %d, sector %d, size %d",
1422 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423} /* tell_sector */
1424
Joe Perchesb46df352010-03-10 15:20:46 -08001425static void print_errors(void)
1426{
1427 DPRINT("");
1428 if (ST0 & ST0_ECE) {
1429 pr_cont("Recalibrate failed!");
1430 } else if (ST2 & ST2_CRC) {
1431 pr_cont("data CRC error");
1432 tell_sector();
1433 } else if (ST1 & ST1_CRC) {
1434 pr_cont("CRC error");
1435 tell_sector();
1436 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1437 (ST2 & ST2_MAM)) {
1438 if (!probing) {
1439 pr_cont("sector not found");
1440 tell_sector();
1441 } else
1442 pr_cont("probe failed...");
1443 } else if (ST2 & ST2_WC) { /* seek error */
1444 pr_cont("wrong cylinder");
1445 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1446 pr_cont("bad cylinder");
1447 } else {
1448 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1449 ST0, ST1, ST2);
1450 tell_sector();
1451 }
1452 pr_cont("\n");
1453}
1454
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455/*
1456 * OK, this error interpreting routine is called after a
1457 * DMA read/write has succeeded
1458 * or failed, so we check the results, and copy any buffers.
1459 * hhb: Added better error reporting.
1460 * ak: Made this into a separate routine.
1461 */
1462static int interpret_errors(void)
1463{
1464 char bad;
1465
1466 if (inr != 7) {
1467 DPRINT("-- FDC reply error");
1468 FDCS->reset = 1;
1469 return 1;
1470 }
1471
1472 /* check IC to find cause of interrupt */
1473 switch (ST0 & ST0_INTR) {
1474 case 0x40: /* error occurred during command execution */
1475 if (ST1 & ST1_EOC)
1476 return 0; /* occurs with pseudo-DMA */
1477 bad = 1;
1478 if (ST1 & ST1_WP) {
1479 DPRINT("Drive is write protected\n");
1480 CLEARF(FD_DISK_WRITABLE);
1481 cont->done(0);
1482 bad = 2;
1483 } else if (ST1 & ST1_ND) {
1484 SETF(FD_NEED_TWADDLE);
1485 } else if (ST1 & ST1_OR) {
1486 if (DP->flags & FTD_MSG)
1487 DPRINT("Over/Underrun - retrying\n");
1488 bad = 0;
1489 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001490 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 }
1492 if (ST2 & ST2_WC || ST2 & ST2_BC)
1493 /* wrong cylinder => recal */
1494 DRS->track = NEED_2_RECAL;
1495 return bad;
1496 case 0x80: /* invalid command given */
1497 DPRINT("Invalid FDC command given!\n");
1498 cont->done(0);
1499 return 2;
1500 case 0xc0:
1501 DPRINT("Abnormal termination caused by polling\n");
1502 cont->error();
1503 return 2;
1504 default: /* (0) Normal command termination */
1505 return 0;
1506 }
1507}
1508
1509/*
1510 * This routine is called when everything should be correctly set up
1511 * for the transfer (i.e. floppy motor is on, the correct floppy is
1512 * selected, and the head is sitting on the right track).
1513 */
1514static void setup_rw_floppy(void)
1515{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001516 int i;
1517 int r;
1518 int flags;
1519 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 unsigned long ready_date;
1521 timeout_fn function;
1522
1523 flags = raw_cmd->flags;
1524 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1525 flags |= FD_RAW_INTR;
1526
1527 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1528 ready_date = DRS->spinup_date + DP->spinup;
1529 /* If spinup will take a long time, rerun scandrives
1530 * again just before spinup completion. Beware that
1531 * after scandrives, we must again wait for selection.
1532 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001533 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 ready_date -= DP->select_delay;
Joe Perchesa0a52d62010-03-10 15:20:52 -08001535 function = (timeout_fn)floppy_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 } else
Joe Perchesa0a52d62010-03-10 15:20:52 -08001537 function = (timeout_fn)setup_rw_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538
1539 /* wait until the floppy is spinning fast enough */
1540 if (fd_wait_for_completion(ready_date, function))
1541 return;
1542 }
1543 dflags = DRS->flags;
1544
1545 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1546 setup_DMA();
1547
1548 if (flags & FD_RAW_INTR)
1549 do_floppy = main_command_interrupt;
1550
1551 r = 0;
1552 for (i = 0; i < raw_cmd->cmd_count; i++)
1553 r |= output_byte(raw_cmd->cmd[i]);
1554
1555 debugt("rw_command: ");
1556
1557 if (r) {
1558 cont->error();
1559 reset_fdc();
1560 return;
1561 }
1562
1563 if (!(flags & FD_RAW_INTR)) {
1564 inr = result();
1565 cont->interrupt();
1566 } else if (flags & FD_RAW_NEED_DISK)
1567 fd_watchdog();
1568}
1569
1570static int blind_seek;
1571
1572/*
1573 * This is the routine called after every seek (or recalibrate) interrupt
1574 * from the floppy controller.
1575 */
1576static void seek_interrupt(void)
1577{
1578 debugt("seek interrupt:");
1579 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1580 DPRINT("seek failed\n");
1581 DRS->track = NEED_2_RECAL;
1582 cont->error();
1583 cont->redo();
1584 return;
1585 }
1586 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
Joe Perches87f530d2010-03-10 15:20:54 -08001587 debug_dcl(DP->flags,
1588 "clearing NEWCHANGE flag because of effective seek\n");
1589 debug_dcl(DP->flags, "jiffies=%lu\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 CLEARF(FD_DISK_NEWCHANGE); /* effective seek */
1591 DRS->select_date = jiffies;
1592 }
1593 DRS->track = ST1;
1594 floppy_ready();
1595}
1596
1597static void check_wp(void)
1598{
1599 if (TESTF(FD_VERIFY)) {
1600 /* check write protection */
1601 output_byte(FD_GETSTATUS);
1602 output_byte(UNIT(current_drive));
1603 if (result() != 1) {
1604 FDCS->reset = 1;
1605 return;
1606 }
1607 CLEARF(FD_VERIFY);
1608 CLEARF(FD_NEED_TWADDLE);
Joe Perches87f530d2010-03-10 15:20:54 -08001609 debug_dcl(DP->flags,
1610 "checking whether disk is write protected\n");
1611 debug_dcl(DP->flags, "wp=%x\n", ST3 & 0x40);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 if (!(ST3 & 0x40))
1613 SETF(FD_DISK_WRITABLE);
1614 else
1615 CLEARF(FD_DISK_WRITABLE);
1616 }
1617}
1618
1619static void seek_floppy(void)
1620{
1621 int track;
1622
1623 blind_seek = 0;
1624
Joe Perches87f530d2010-03-10 15:20:54 -08001625 debug_dcl(DP->flags, "calling disk change from seek\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626
1627 if (!TESTF(FD_DISK_NEWCHANGE) &&
1628 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1629 /* the media changed flag should be cleared after the seek.
1630 * If it isn't, this means that there is really no disk in
1631 * the drive.
1632 */
1633 SETF(FD_DISK_CHANGED);
1634 cont->done(0);
1635 cont->redo();
1636 return;
1637 }
1638 if (DRS->track <= NEED_1_RECAL) {
1639 recalibrate_floppy();
1640 return;
1641 } else if (TESTF(FD_DISK_NEWCHANGE) &&
1642 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1643 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1644 /* we seek to clear the media-changed condition. Does anybody
1645 * know a more elegant way, which works on all drives? */
1646 if (raw_cmd->track)
1647 track = raw_cmd->track - 1;
1648 else {
1649 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1650 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1651 blind_seek = 1;
1652 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1653 }
1654 track = 1;
1655 }
1656 } else {
1657 check_wp();
1658 if (raw_cmd->track != DRS->track &&
1659 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1660 track = raw_cmd->track;
1661 else {
1662 setup_rw_floppy();
1663 return;
1664 }
1665 }
1666
1667 do_floppy = seek_interrupt;
1668 output_byte(FD_SEEK);
1669 output_byte(UNIT(current_drive));
Joe Perches2300f902010-03-10 15:20:49 -08001670 if (output_byte(track) < 0) {
1671 reset_fdc();
1672 return;
1673 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 debugt("seek command:");
1675}
1676
1677static void recal_interrupt(void)
1678{
1679 debugt("recal interrupt:");
1680 if (inr != 2)
1681 FDCS->reset = 1;
1682 else if (ST0 & ST0_ECE) {
1683 switch (DRS->track) {
1684 case NEED_1_RECAL:
1685 debugt("recal interrupt need 1 recal:");
1686 /* after a second recalibrate, we still haven't
1687 * reached track 0. Probably no drive. Raise an
1688 * error, as failing immediately might upset
1689 * computers possessed by the Devil :-) */
1690 cont->error();
1691 cont->redo();
1692 return;
1693 case NEED_2_RECAL:
1694 debugt("recal interrupt need 2 recal:");
1695 /* If we already did a recalibrate,
1696 * and we are not at track 0, this
1697 * means we have moved. (The only way
1698 * not to move at recalibration is to
1699 * be already at track 0.) Clear the
1700 * new change flag */
Joe Perches87f530d2010-03-10 15:20:54 -08001701 debug_dcl(DP->flags,
1702 "clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703
1704 CLEARF(FD_DISK_NEWCHANGE);
1705 DRS->select_date = jiffies;
1706 /* fall through */
1707 default:
1708 debugt("recal interrupt default:");
1709 /* Recalibrate moves the head by at
1710 * most 80 steps. If after one
1711 * recalibrate we don't have reached
1712 * track 0, this might mean that we
1713 * started beyond track 80. Try
1714 * again. */
1715 DRS->track = NEED_1_RECAL;
1716 break;
1717 }
1718 } else
1719 DRS->track = ST1;
1720 floppy_ready();
1721}
1722
1723static void print_result(char *message, int inr)
1724{
1725 int i;
1726
1727 DPRINT("%s ", message);
1728 if (inr >= 0)
1729 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001730 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1731 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732}
1733
1734/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001735irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 int do_print;
1738 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001739 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740
1741 lasthandler = handler;
1742 interruptjiffies = jiffies;
1743
1744 f = claim_dma_lock();
1745 fd_disable_dma();
1746 release_dma_lock(f);
1747
1748 floppy_enable_hlt();
1749 do_floppy = NULL;
1750 if (fdc >= N_FDC || FDCS->address == -1) {
1751 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001752 pr_info("DOR0=%x\n", fdc_state[0].dor);
1753 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
1754 pr_info("handler=%p\n", handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 is_alive("bizarre fdc");
1756 return IRQ_NONE;
1757 }
1758
1759 FDCS->reset = 0;
1760 /* We have to clear the reset flag here, because apparently on boxes
1761 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1762 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1763 * emission of the SENSEI's.
1764 * It is OK to emit floppy commands because we are in an interrupt
1765 * handler here, and thus we have to fear no interference of other
1766 * activity.
1767 */
1768
1769 do_print = !handler && print_unex && !initialising;
1770
1771 inr = result();
1772 if (do_print)
1773 print_result("unexpected interrupt", inr);
1774 if (inr == 0) {
1775 int max_sensei = 4;
1776 do {
1777 output_byte(FD_SENSEI);
1778 inr = result();
1779 if (do_print)
1780 print_result("sensei", inr);
1781 max_sensei--;
1782 } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2
1783 && max_sensei);
1784 }
1785 if (!handler) {
1786 FDCS->reset = 1;
1787 return IRQ_NONE;
1788 }
1789 schedule_bh(handler);
1790 is_alive("normal interrupt end");
1791
1792 /* FIXME! Was it really for us? */
1793 return IRQ_HANDLED;
1794}
1795
1796static void recalibrate_floppy(void)
1797{
1798 debugt("recalibrate floppy:");
1799 do_floppy = recal_interrupt;
1800 output_byte(FD_RECALIBRATE);
Joe Perches2300f902010-03-10 15:20:49 -08001801 if (output_byte(UNIT(current_drive)) < 0) {
1802 reset_fdc();
1803 return;
1804 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805}
1806
1807/*
1808 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1809 */
1810static void reset_interrupt(void)
1811{
1812 debugt("reset interrupt:");
1813 result(); /* get the status ready for set_fdc */
1814 if (FDCS->reset) {
Joe Perchesb46df352010-03-10 15:20:46 -08001815 pr_info("reset set in interrupt, calling %p\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 cont->error(); /* a reset just after a reset. BAD! */
1817 }
1818 cont->redo();
1819}
1820
1821/*
1822 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1823 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1824 */
1825static void reset_fdc(void)
1826{
1827 unsigned long flags;
1828
1829 do_floppy = reset_interrupt;
1830 FDCS->reset = 0;
1831 reset_fdc_info(0);
1832
1833 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1834 /* Irrelevant for systems with true DMA (i386). */
1835
1836 flags = claim_dma_lock();
1837 fd_disable_dma();
1838 release_dma_lock(flags);
1839
1840 if (FDCS->version >= FDC_82072A)
1841 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1842 else {
1843 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1844 udelay(FD_RESET_DELAY);
1845 fd_outb(FDCS->dor, FD_DOR);
1846 }
1847}
1848
1849static void show_floppy(void)
1850{
1851 int i;
1852
Joe Perchesb46df352010-03-10 15:20:46 -08001853 pr_info("\n");
1854 pr_info("floppy driver state\n");
1855 pr_info("-------------------\n");
1856 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%p\n",
1857 jiffies, interruptjiffies, jiffies - interruptjiffies,
1858 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859
1860#ifdef FLOPPY_SANITY_CHECK
Joe Perchesb46df352010-03-10 15:20:46 -08001861 pr_info("timeout_message=%s\n", timeout_message);
1862 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001864 pr_info("%2x %2x %lu\n",
1865 output_log[(i + output_log_pos) % OLOGSIZE].data,
1866 output_log[(i + output_log_pos) % OLOGSIZE].status,
1867 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1868 pr_info("last result at %lu\n", resultjiffies);
1869 pr_info("last redo_fd_request at %lu\n", lastredo);
1870 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1871 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872#endif
1873
Joe Perchesb46df352010-03-10 15:20:46 -08001874 pr_info("status=%x\n", fd_inb(FD_STATUS));
1875 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 if (do_floppy)
Joe Perchesb46df352010-03-10 15:20:46 -08001877 pr_info("do_floppy=%p\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001878 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08001879 pr_info("floppy_work.func=%p\n", floppy_work.func);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08001881 pr_info("fd_timer.function=%p\n", fd_timer.function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 if (timer_pending(&fd_timeout)) {
Joe Perchesb46df352010-03-10 15:20:46 -08001883 pr_info("timer_function=%p\n", fd_timeout.function);
1884 pr_info("expires=%lu\n", fd_timeout.expires - jiffies);
1885 pr_info("now=%lu\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 }
Joe Perchesb46df352010-03-10 15:20:46 -08001887 pr_info("cont=%p\n", cont);
1888 pr_info("current_req=%p\n", current_req);
1889 pr_info("command_status=%d\n", command_status);
1890 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891}
1892
1893static void floppy_shutdown(unsigned long data)
1894{
1895 unsigned long flags;
1896
1897 if (!initialising)
1898 show_floppy();
1899 cancel_activity();
1900
1901 floppy_enable_hlt();
1902
1903 flags = claim_dma_lock();
1904 fd_disable_dma();
1905 release_dma_lock(flags);
1906
1907 /* avoid dma going to a random drive after shutdown */
1908
1909 if (!initialising)
1910 DPRINT("floppy timeout called\n");
1911 FDCS->reset = 1;
1912 if (cont) {
1913 cont->done(0);
1914 cont->redo(); /* this will recall reset when needed */
1915 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001916 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 process_fd_request();
1918 }
1919 is_alive("floppy shutdown");
1920}
1921
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001923static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001925 int mask;
1926 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927
1928 mask = 0xfc;
1929 data = UNIT(current_drive);
1930 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1931 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1932 set_debugt();
1933 /* no read since this drive is running */
1934 DRS->first_read_date = 0;
1935 /* note motor start time if motor is not yet running */
1936 DRS->spinup_date = jiffies;
1937 data |= (0x10 << UNIT(current_drive));
1938 }
1939 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1940 mask &= ~(0x10 << UNIT(current_drive));
1941
1942 /* starts motor and selects floppy */
1943 del_timer(motor_off_timer + current_drive);
1944 set_dor(fdc, mask, data);
1945
1946 /* wait_for_completion also schedules reset if needed. */
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001947 return fd_wait_for_completion(DRS->select_date + DP->select_delay,
1948 (timeout_fn)function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949}
1950
1951static void floppy_ready(void)
1952{
Joe Perches045f9832010-03-10 15:20:47 -08001953 if (FDCS->reset) {
1954 reset_fdc();
1955 return;
1956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 if (start_motor(floppy_ready))
1958 return;
1959 if (fdc_dtr())
1960 return;
1961
Joe Perches87f530d2010-03-10 15:20:54 -08001962 debug_dcl(DP->flags, "calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1964 disk_change(current_drive) && !DP->select_delay)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001965 twaddle(); /* this clears the dcl on certain
1966 * drive/controller combinations */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967
1968#ifdef fd_chose_dma_mode
1969 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1970 unsigned long flags = claim_dma_lock();
1971 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1972 release_dma_lock(flags);
1973 }
1974#endif
1975
1976 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1977 perpendicular_mode();
1978 fdc_specify(); /* must be done here because of hut, hlt ... */
1979 seek_floppy();
1980 } else {
1981 if ((raw_cmd->flags & FD_RAW_READ) ||
1982 (raw_cmd->flags & FD_RAW_WRITE))
1983 fdc_specify();
1984 setup_rw_floppy();
1985 }
1986}
1987
1988static void floppy_start(void)
1989{
1990 reschedule_timeout(current_reqD, "floppy start", 0);
1991
1992 scandrives();
Joe Perches87f530d2010-03-10 15:20:54 -08001993 debug_dcl(DP->flags, "setting NEWCHANGE in floppy_start\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 SETF(FD_DISK_NEWCHANGE);
1995 floppy_ready();
1996}
1997
1998/*
1999 * ========================================================================
2000 * here ends the bottom half. Exported routines are:
2001 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
2002 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
2003 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
2004 * and set_dor.
2005 * ========================================================================
2006 */
2007/*
2008 * General purpose continuations.
2009 * ==============================
2010 */
2011
2012static void do_wakeup(void)
2013{
2014 reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);
2015 cont = NULL;
2016 command_status += 2;
2017 wake_up(&command_done);
2018}
2019
2020static struct cont_t wakeup_cont = {
2021 .interrupt = empty,
2022 .redo = do_wakeup,
2023 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002024 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025};
2026
2027static struct cont_t intr_cont = {
2028 .interrupt = empty,
2029 .redo = process_fd_request,
2030 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002031 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032};
2033
Jesper Juhl06f748c2007-10-16 23:30:57 -07002034static int wait_til_done(void (*handler)(void), int interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035{
2036 int ret;
2037
2038 schedule_bh(handler);
2039
2040 if (command_status < 2 && NO_SIGNAL) {
2041 DECLARE_WAITQUEUE(wait, current);
2042
2043 add_wait_queue(&command_done, &wait);
2044 for (;;) {
2045 set_current_state(interruptible ?
2046 TASK_INTERRUPTIBLE :
2047 TASK_UNINTERRUPTIBLE);
2048
2049 if (command_status >= 2 || !NO_SIGNAL)
2050 break;
2051
2052 is_alive("wait_til_done");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 schedule();
2054 }
2055
2056 set_current_state(TASK_RUNNING);
2057 remove_wait_queue(&command_done, &wait);
2058 }
2059
2060 if (command_status < 2) {
2061 cancel_activity();
2062 cont = &intr_cont;
2063 reset_fdc();
2064 return -EINTR;
2065 }
2066
2067 if (FDCS->reset)
2068 command_status = FD_COMMAND_ERROR;
2069 if (command_status == FD_COMMAND_OKAY)
2070 ret = 0;
2071 else
2072 ret = -EIO;
2073 command_status = FD_COMMAND_NONE;
2074 return ret;
2075}
2076
2077static void generic_done(int result)
2078{
2079 command_status = result;
2080 cont = &wakeup_cont;
2081}
2082
2083static void generic_success(void)
2084{
2085 cont->done(1);
2086}
2087
2088static void generic_failure(void)
2089{
2090 cont->done(0);
2091}
2092
2093static void success_and_wakeup(void)
2094{
2095 generic_success();
2096 cont->redo();
2097}
2098
2099/*
2100 * formatting and rw support.
2101 * ==========================
2102 */
2103
2104static int next_valid_format(void)
2105{
2106 int probed_format;
2107
2108 probed_format = DRS->probed_format;
2109 while (1) {
2110 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2111 DRS->probed_format = 0;
2112 return 1;
2113 }
2114 if (floppy_type[DP->autodetect[probed_format]].sect) {
2115 DRS->probed_format = probed_format;
2116 return 0;
2117 }
2118 probed_format++;
2119 }
2120}
2121
2122static void bad_flp_intr(void)
2123{
2124 int err_count;
2125
2126 if (probing) {
2127 DRS->probed_format++;
2128 if (!next_valid_format())
2129 return;
2130 }
2131 err_count = ++(*errors);
2132 INFBOUND(DRWE->badness, err_count);
2133 if (err_count > DP->max_errors.abort)
2134 cont->done(0);
2135 if (err_count > DP->max_errors.reset)
2136 FDCS->reset = 1;
2137 else if (err_count > DP->max_errors.recal)
2138 DRS->track = NEED_2_RECAL;
2139}
2140
2141static void set_floppy(int drive)
2142{
2143 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002144
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 if (type)
2146 _floppy = floppy_type + type;
2147 else
2148 _floppy = current_type[drive];
2149}
2150
2151/*
2152 * formatting support.
2153 * ===================
2154 */
2155static void format_interrupt(void)
2156{
2157 switch (interpret_errors()) {
2158 case 1:
2159 cont->error();
2160 case 2:
2161 break;
2162 case 0:
2163 cont->done(1);
2164 }
2165 cont->redo();
2166}
2167
2168#define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2)
Joe Perches48c8cee2010-03-10 15:20:45 -08002169#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002171
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172static void setup_format_params(int track)
2173{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002174 int n;
2175 int il;
2176 int count;
2177 int head_shift;
2178 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 struct fparm {
2180 unsigned char track, head, sect, size;
2181 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182
2183 raw_cmd = &default_raw_cmd;
2184 raw_cmd->track = track;
2185
Joe Perches48c8cee2010-03-10 15:20:45 -08002186 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2187 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 raw_cmd->rate = _floppy->rate & 0x43;
2189 raw_cmd->cmd_count = NR_F;
2190 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2191 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2192 F_SIZECODE = FD_SIZECODE(_floppy);
2193 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2194 F_GAP = _floppy->fmt_gap;
2195 F_FILL = FD_FILL_BYTE;
2196
2197 raw_cmd->kernel_data = floppy_track_buffer;
2198 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2199
2200 /* allow for about 30ms for data transport per track */
2201 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2202
2203 /* a ``cylinder'' is two tracks plus a little stepping time */
2204 track_shift = 2 * head_shift + 3;
2205
2206 /* position of logical sector 1 on this track */
2207 n = (track_shift * format_req.track + head_shift * format_req.head)
2208 % F_SECT_PER_TRACK;
2209
2210 /* determine interleave */
2211 il = 1;
2212 if (_floppy->fmt_gap < 0x22)
2213 il++;
2214
2215 /* initialize field */
2216 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2217 here[count].track = format_req.track;
2218 here[count].head = format_req.head;
2219 here[count].sect = 0;
2220 here[count].size = F_SIZECODE;
2221 }
2222 /* place logical sectors */
2223 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2224 here[n].sect = count;
2225 n = (n + il) % F_SECT_PER_TRACK;
2226 if (here[n].sect) { /* sector busy, find next free sector */
2227 ++n;
2228 if (n >= F_SECT_PER_TRACK) {
2229 n -= F_SECT_PER_TRACK;
2230 while (here[n].sect)
2231 ++n;
2232 }
2233 }
2234 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002235 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002237 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 }
2239}
2240
2241static void redo_format(void)
2242{
2243 buffer_track = -1;
2244 setup_format_params(format_req.track << STRETCH(_floppy));
2245 floppy_start();
2246 debugt("queue format request");
2247}
2248
2249static struct cont_t format_cont = {
2250 .interrupt = format_interrupt,
2251 .redo = redo_format,
2252 .error = bad_flp_intr,
2253 .done = generic_done
2254};
2255
2256static int do_format(int drive, struct format_descr *tmp_format_req)
2257{
2258 int ret;
2259
Joe Perches52a0d612010-03-10 15:20:53 -08002260 if (lock_fdc(drive, 1))
2261 return -EINTR;
2262
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 set_floppy(drive);
2264 if (!_floppy ||
2265 _floppy->track > DP->tracks ||
2266 tmp_format_req->track >= _floppy->track ||
2267 tmp_format_req->head >= _floppy->head ||
2268 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2269 !_floppy->fmt_gap) {
2270 process_fd_request();
2271 return -EINVAL;
2272 }
2273 format_req = *tmp_format_req;
2274 format_errors = 0;
2275 cont = &format_cont;
2276 errors = &format_errors;
2277 IWAIT(redo_format);
2278 process_fd_request();
2279 return ret;
2280}
2281
2282/*
2283 * Buffer read/write and support
2284 * =============================
2285 */
2286
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002287static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288{
2289 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002290 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291
2292 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002293 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002294 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002295 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297
2298 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002299 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 current_req = NULL;
2301}
2302
2303/* new request_done. Can handle physical sectors which are smaller than a
2304 * logical buffer */
2305static void request_done(int uptodate)
2306{
2307 struct request_queue *q = floppy_queue;
2308 struct request *req = current_req;
2309 unsigned long flags;
2310 int block;
2311
2312 probing = 0;
Joe Perchesb46df352010-03-10 15:20:46 -08002313 reschedule_timeout(MAXTIMEOUT, "request done", uptodate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314
2315 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002316 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 return;
2318 }
2319
2320 if (uptodate) {
2321 /* maintain values for invalidation on geometry
2322 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002323 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 INFBOUND(DRS->maxblock, block);
2325 if (block > _floppy->sect)
2326 DRS->maxtrack = 1;
2327
2328 /* unlock chained buffers */
2329 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002330 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 spin_unlock_irqrestore(q->queue_lock, flags);
2332 } else {
2333 if (rq_data_dir(req) == WRITE) {
2334 /* record write error information */
2335 DRWE->write_errors++;
2336 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002337 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 DRWE->first_error_generation = DRS->generation;
2339 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002340 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 DRWE->last_error_generation = DRS->generation;
2342 }
2343 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002344 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 spin_unlock_irqrestore(q->queue_lock, flags);
2346 }
2347}
2348
2349/* Interrupt handler evaluating the result of the r/w operation */
2350static void rw_interrupt(void)
2351{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002352 int eoc;
2353 int ssize;
2354 int heads;
2355 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356
2357 if (R_HEAD >= 2) {
2358 /* some Toshiba floppy controllers occasionnally seem to
2359 * return bogus interrupts after read/write operations, which
2360 * can be recognized by a bad head number (>= 2) */
2361 return;
2362 }
2363
2364 if (!DRS->first_read_date)
2365 DRS->first_read_date = jiffies;
2366
2367 nr_sectors = 0;
2368 CODE2SIZE;
2369
2370 if (ST1 & ST1_EOC)
2371 eoc = 1;
2372 else
2373 eoc = 0;
2374
2375 if (COMMAND & 0x80)
2376 heads = 2;
2377 else
2378 heads = 1;
2379
2380 nr_sectors = (((R_TRACK - TRACK) * heads +
2381 R_HEAD - HEAD) * SECT_PER_TRACK +
2382 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2383
2384#ifdef FLOPPY_SANITY_CHECK
2385 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002386 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 DPRINT("long rw: %x instead of %lx\n",
2388 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002389 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2390 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2391 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2392 pr_info("heads=%d eoc=%d\n", heads, eoc);
2393 pr_info("spt=%d st=%d ss=%d\n",
2394 SECT_PER_TRACK, fsector_t, ssize);
2395 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 }
2397#endif
2398
2399 nr_sectors -= in_sector_offset;
2400 INFBOUND(nr_sectors, 0);
2401 SUPBOUND(current_count_sectors, nr_sectors);
2402
2403 switch (interpret_errors()) {
2404 case 2:
2405 cont->redo();
2406 return;
2407 case 1:
2408 if (!current_count_sectors) {
2409 cont->error();
2410 cont->redo();
2411 return;
2412 }
2413 break;
2414 case 0:
2415 if (!current_count_sectors) {
2416 cont->redo();
2417 return;
2418 }
2419 current_type[current_drive] = _floppy;
2420 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2421 break;
2422 }
2423
2424 if (probing) {
2425 if (DP->flags & FTD_MSG)
2426 DPRINT("Auto-detected floppy type %s in fd%d\n",
2427 _floppy->name, current_drive);
2428 current_type[current_drive] = _floppy;
2429 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2430 probing = 0;
2431 }
2432
2433 if (CT(COMMAND) != FD_READ ||
2434 raw_cmd->kernel_data == current_req->buffer) {
2435 /* transfer directly from buffer */
2436 cont->done(1);
2437 } else if (CT(COMMAND) == FD_READ) {
2438 buffer_track = raw_cmd->track;
2439 buffer_drive = current_drive;
2440 INFBOUND(buffer_max, nr_sectors + fsector_t);
2441 }
2442 cont->redo();
2443}
2444
2445/* Compute maximal contiguous buffer size. */
2446static int buffer_chain_size(void)
2447{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 struct bio_vec *bv;
NeilBrown5705f702007-09-25 12:35:59 +02002449 int size;
2450 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 char *base;
2452
2453 base = bio_data(current_req->bio);
2454 size = 0;
2455
NeilBrown5705f702007-09-25 12:35:59 +02002456 rq_for_each_segment(bv, current_req, iter) {
2457 if (page_address(bv->bv_page) + bv->bv_offset != base + size)
2458 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459
NeilBrown5705f702007-09-25 12:35:59 +02002460 size += bv->bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 }
2462
2463 return size >> 9;
2464}
2465
2466/* Compute the maximal transfer size */
2467static int transfer_size(int ssize, int max_sector, int max_size)
2468{
2469 SUPBOUND(max_sector, fsector_t + max_size);
2470
2471 /* alignment */
2472 max_sector -= (max_sector % _floppy->sect) % ssize;
2473
2474 /* transfer size, beginning not aligned */
2475 current_count_sectors = max_sector - fsector_t;
2476
2477 return max_sector;
2478}
2479
2480/*
2481 * Move data from/to the track buffer to/from the buffer cache.
2482 */
2483static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2484{
2485 int remaining; /* number of transferred 512-byte sectors */
2486 struct bio_vec *bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002487 char *buffer;
2488 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002489 int size;
2490 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491
2492 max_sector = transfer_size(ssize,
2493 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002494 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495
2496 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002497 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002499 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500
2501 remaining = current_count_sectors << 9;
2502#ifdef FLOPPY_SANITY_CHECK
Tejun Heo1011c1b2009-05-07 22:24:45 +09002503 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002505 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2506 pr_info("remaining=%d\n", remaining >> 9);
2507 pr_info("current_req->nr_sectors=%u\n",
2508 blk_rq_sectors(current_req));
2509 pr_info("current_req->current_nr_sectors=%u\n",
2510 blk_rq_cur_sectors(current_req));
2511 pr_info("max_sector=%d\n", max_sector);
2512 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 }
2514#endif
2515
2516 buffer_max = max(max_sector, buffer_max);
2517
2518 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2519
Tejun Heo1011c1b2009-05-07 22:24:45 +09002520 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521
NeilBrown5705f702007-09-25 12:35:59 +02002522 rq_for_each_segment(bv, current_req, iter) {
2523 if (!remaining)
2524 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525
NeilBrown5705f702007-09-25 12:35:59 +02002526 size = bv->bv_len;
2527 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528
NeilBrown5705f702007-09-25 12:35:59 +02002529 buffer = page_address(bv->bv_page) + bv->bv_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530#ifdef FLOPPY_SANITY_CHECK
NeilBrown5705f702007-09-25 12:35:59 +02002531 if (dma_buffer + size >
2532 floppy_track_buffer + (max_buffer_sectors << 10) ||
2533 dma_buffer < floppy_track_buffer) {
2534 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002535 (int)((floppy_track_buffer - dma_buffer) >> 9));
2536 pr_info("fsector_t=%d buffer_min=%d\n",
2537 fsector_t, buffer_min);
2538 pr_info("current_count_sectors=%ld\n",
2539 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002541 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002542 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002543 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002544 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 }
NeilBrown5705f702007-09-25 12:35:59 +02002546 if (((unsigned long)buffer) % 512)
2547 DPRINT("%p buffer not aligned\n", buffer);
2548#endif
2549 if (CT(COMMAND) == FD_READ)
2550 memcpy(buffer, dma_buffer, size);
2551 else
2552 memcpy(dma_buffer, buffer, size);
2553
2554 remaining -= size;
2555 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 }
2557#ifdef FLOPPY_SANITY_CHECK
2558 if (remaining) {
2559 if (remaining > 0)
2560 max_sector -= remaining >> 9;
2561 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2562 }
2563#endif
2564}
2565
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566/* work around a bug in pseudo DMA
2567 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2568 * sending data. Hence we need a different way to signal the
2569 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2570 * does not work with MT, hence we can only transfer one head at
2571 * a time
2572 */
2573static void virtualdmabug_workaround(void)
2574{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002575 int hard_sectors;
2576 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577
2578 if (CT(COMMAND) == FD_WRITE) {
2579 COMMAND &= ~0x80; /* switch off multiple track mode */
2580
2581 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2582 end_sector = SECTOR + hard_sectors - 1;
2583#ifdef FLOPPY_SANITY_CHECK
2584 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002585 pr_info("too many sectors %d > %d\n",
2586 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 return;
2588 }
2589#endif
Joe Perches48c8cee2010-03-10 15:20:45 -08002590 SECT_PER_TRACK = end_sector;
2591 /* make sure SECT_PER_TRACK
2592 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 }
2594}
2595
2596/*
2597 * Formulate a read/write request.
2598 * this routine decides where to load the data (directly to buffer, or to
2599 * tmp floppy area), how much data to load (the size of the buffer, the whole
2600 * track, or a single sector)
2601 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2602 * allocation on the fly, it should be done here. No other part should need
2603 * modification.
2604 */
2605
2606static int make_raw_rw_request(void)
2607{
2608 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002609 int max_sector;
2610 int max_size;
2611 int tracksize;
2612 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613
2614 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002615 pr_info("VFS: Block I/O scheduled on unopened device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 return 0;
2617 }
2618
2619 set_fdc((long)current_req->rq_disk->private_data);
2620
2621 raw_cmd = &default_raw_cmd;
2622 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
2623 FD_RAW_NEED_SEEK;
2624 raw_cmd->cmd_count = NR_RW;
2625 if (rq_data_dir(current_req) == READ) {
2626 raw_cmd->flags |= FD_RAW_READ;
2627 COMMAND = FM_MODE(_floppy, FD_READ);
2628 } else if (rq_data_dir(current_req) == WRITE) {
2629 raw_cmd->flags |= FD_RAW_WRITE;
2630 COMMAND = FM_MODE(_floppy, FD_WRITE);
2631 } else {
2632 DPRINT("make_raw_rw_request: unknown command\n");
2633 return 0;
2634 }
2635
2636 max_sector = _floppy->sect * _floppy->head;
2637
Tejun Heo83096eb2009-05-07 22:24:39 +09002638 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2639 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002641 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 current_count_sectors = 1;
2643 return 1;
2644 } else
2645 return 0;
2646 }
2647 HEAD = fsector_t / _floppy->sect;
2648
Keith Wansbrough9e491842008-09-22 14:57:17 -07002649 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 TESTF(FD_NEED_TWADDLE)) && fsector_t < _floppy->sect)
2651 max_sector = _floppy->sect;
2652
2653 /* 2M disks have phantom sectors on the first track */
2654 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2655 max_sector = 2 * _floppy->sect / 3;
2656 if (fsector_t >= max_sector) {
2657 current_count_sectors =
2658 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002659 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 return 1;
2661 }
2662 SIZECODE = 2;
2663 } else
2664 SIZECODE = FD_SIZECODE(_floppy);
2665 raw_cmd->rate = _floppy->rate & 0x43;
2666 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2667 raw_cmd->rate = 1;
2668
2669 if (SIZECODE)
2670 SIZECODE2 = 0xff;
2671 else
2672 SIZECODE2 = 0x80;
2673 raw_cmd->track = TRACK << STRETCH(_floppy);
2674 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2675 GAP = _floppy->gap;
2676 CODE2SIZE;
2677 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2678 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002679 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680
2681 /* tracksize describes the size which can be filled up with sectors
2682 * of size ssize.
2683 */
2684 tracksize = _floppy->sect - _floppy->sect % ssize;
2685 if (tracksize < _floppy->sect) {
2686 SECT_PER_TRACK++;
2687 if (tracksize <= fsector_t % _floppy->sect)
2688 SECTOR--;
2689
2690 /* if we are beyond tracksize, fill up using smaller sectors */
2691 while (tracksize <= fsector_t % _floppy->sect) {
2692 while (tracksize + ssize > _floppy->sect) {
2693 SIZECODE--;
2694 ssize >>= 1;
2695 }
2696 SECTOR++;
2697 SECT_PER_TRACK++;
2698 tracksize += ssize;
2699 }
2700 max_sector = HEAD * _floppy->sect + tracksize;
2701 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2702 max_sector = _floppy->sect;
2703 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2704 /* for virtual DMA bug workaround */
2705 max_sector = _floppy->sect;
2706 }
2707
2708 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2709 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002710 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 if ((raw_cmd->track == buffer_track) &&
2712 (current_drive == buffer_drive) &&
2713 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2714 /* data already in track buffer */
2715 if (CT(COMMAND) == FD_READ) {
2716 copy_buffer(1, max_sector, buffer_max);
2717 return 1;
2718 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002719 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 if (CT(COMMAND) == FD_WRITE) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002721 unsigned int sectors;
2722
2723 sectors = fsector_t + blk_rq_sectors(current_req);
2724 if (sectors > ssize && sectors < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 max_size = ssize + ssize;
2726 else
2727 max_size = ssize;
2728 }
2729 raw_cmd->flags &= ~FD_RAW_WRITE;
2730 raw_cmd->flags |= FD_RAW_READ;
2731 COMMAND = FM_MODE(_floppy, FD_READ);
2732 } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) {
2733 unsigned long dma_limit;
2734 int direct, indirect;
2735
2736 indirect =
2737 transfer_size(ssize, max_sector,
2738 max_buffer_sectors * 2) - fsector_t;
2739
2740 /*
2741 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2742 * on a 64 bit machine!
2743 */
2744 max_size = buffer_chain_size();
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002745 dma_limit = (MAX_DMA_ADDRESS -
2746 ((unsigned long)current_req->buffer)) >> 9;
Joe Perchesa81ee542010-03-10 15:20:46 -08002747 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 /* 64 kb boundaries */
2750 if (CROSS_64KB(current_req->buffer, max_size << 9))
2751 max_size = (K_64 -
2752 ((unsigned long)current_req->buffer) %
2753 K_64) >> 9;
2754 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2755 /*
2756 * We try to read tracks, but if we get too many errors, we
2757 * go back to reading just one sector at a time.
2758 *
2759 * This means we should be able to read a sector even if there
2760 * are other bad sectors on this track.
2761 */
2762 if (!direct ||
2763 (indirect * 2 > direct * 3 &&
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002764 *errors < DP->max_errors.read_track &&
2765 ((!probing ||
2766 (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002767 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 } else {
2769 raw_cmd->kernel_data = current_req->buffer;
2770 raw_cmd->length = current_count_sectors << 9;
2771 if (raw_cmd->length == 0) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002772 DPRINT("zero dma transfer attempted from make_raw_request\n");
2773 DPRINT("indirect=%d direct=%d fsector_t=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 indirect, direct, fsector_t);
2775 return 0;
2776 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 virtualdmabug_workaround();
2778 return 2;
2779 }
2780 }
2781
2782 if (CT(COMMAND) == FD_READ)
2783 max_size = max_sector; /* unbounded */
2784
2785 /* claim buffer track if needed */
2786 if (buffer_track != raw_cmd->track || /* bad track */
2787 buffer_drive != current_drive || /* bad drive */
2788 fsector_t > buffer_max ||
2789 fsector_t < buffer_min ||
2790 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002791 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 max_sector > 2 * max_buffer_sectors + buffer_min &&
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002793 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
2794 /* not enough space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 buffer_track = -1;
2796 buffer_drive = current_drive;
2797 buffer_max = buffer_min = aligned_sector_t;
2798 }
2799 raw_cmd->kernel_data = floppy_track_buffer +
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002800 ((aligned_sector_t - buffer_min) << 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801
2802 if (CT(COMMAND) == FD_WRITE) {
2803 /* copy write buffer to track buffer.
2804 * if we get here, we know that the write
2805 * is either aligned or the data already in the buffer
2806 * (buffer will be overwritten) */
2807#ifdef FLOPPY_SANITY_CHECK
2808 if (in_sector_offset && buffer_track == -1)
2809 DPRINT("internal error offset !=0 on write\n");
2810#endif
2811 buffer_track = raw_cmd->track;
2812 buffer_drive = current_drive;
2813 copy_buffer(ssize, max_sector,
2814 2 * max_buffer_sectors + buffer_min);
2815 } else
2816 transfer_size(ssize, max_sector,
2817 2 * max_buffer_sectors + buffer_min -
2818 aligned_sector_t);
2819
2820 /* round up current_count_sectors to get dma xfer size */
2821 raw_cmd->length = in_sector_offset + current_count_sectors;
2822 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2823 raw_cmd->length <<= 9;
2824#ifdef FLOPPY_SANITY_CHECK
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 if ((raw_cmd->length < current_count_sectors << 9) ||
2826 (raw_cmd->kernel_data != current_req->buffer &&
2827 CT(COMMAND) == FD_WRITE &&
2828 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2829 aligned_sector_t < buffer_min)) ||
2830 raw_cmd->length % (128 << SIZECODE) ||
2831 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2832 DPRINT("fractionary current count b=%lx s=%lx\n",
2833 raw_cmd->length, current_count_sectors);
2834 if (raw_cmd->kernel_data != current_req->buffer)
Joe Perchesb46df352010-03-10 15:20:46 -08002835 pr_info("addr=%d, length=%ld\n",
2836 (int)((raw_cmd->kernel_data -
2837 floppy_track_buffer) >> 9),
2838 current_count_sectors);
2839 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2840 fsector_t, aligned_sector_t, max_sector, max_size);
2841 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2842 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2843 COMMAND, SECTOR, HEAD, TRACK);
2844 pr_info("buffer drive=%d\n", buffer_drive);
2845 pr_info("buffer track=%d\n", buffer_track);
2846 pr_info("buffer_min=%d\n", buffer_min);
2847 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 return 0;
2849 }
2850
2851 if (raw_cmd->kernel_data != current_req->buffer) {
2852 if (raw_cmd->kernel_data < floppy_track_buffer ||
2853 current_count_sectors < 0 ||
2854 raw_cmd->length < 0 ||
2855 raw_cmd->kernel_data + raw_cmd->length >
2856 floppy_track_buffer + (max_buffer_sectors << 10)) {
2857 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002858 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2859 fsector_t, buffer_min, raw_cmd->length >> 9);
2860 pr_info("current_count_sectors=%ld\n",
2861 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002863 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002865 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 return 0;
2867 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002868 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002869 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 DPRINT("buffer overrun in direct transfer\n");
2871 return 0;
2872 } else if (raw_cmd->length < current_count_sectors << 9) {
2873 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002874 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2875 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 }
2877 if (raw_cmd->length == 0) {
2878 DPRINT("zero dma transfer attempted from make_raw_request\n");
2879 return 0;
2880 }
2881#endif
2882
2883 virtualdmabug_workaround();
2884 return 2;
2885}
2886
2887static void redo_fd_request(void)
2888{
2889#define REPEAT {request_done(0); continue; }
2890 int drive;
2891 int tmp;
2892
2893 lastredo = jiffies;
2894 if (current_drive < N_DRIVE)
2895 floppy_off(current_drive);
2896
2897 for (;;) {
2898 if (!current_req) {
2899 struct request *req;
2900
2901 spin_lock_irq(floppy_queue->queue_lock);
Tejun Heo9934c8c2009-05-08 11:54:16 +09002902 req = blk_fetch_request(floppy_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 spin_unlock_irq(floppy_queue->queue_lock);
2904 if (!req) {
2905 do_floppy = NULL;
2906 unlock_fdc();
2907 return;
2908 }
2909 current_req = req;
2910 }
2911 drive = (long)current_req->rq_disk->private_data;
2912 set_fdc(drive);
2913 reschedule_timeout(current_reqD, "redo fd request", 0);
2914
2915 set_floppy(drive);
2916 raw_cmd = &default_raw_cmd;
2917 raw_cmd->flags = 0;
2918 if (start_motor(redo_fd_request))
2919 return;
2920 disk_change(current_drive);
2921 if (test_bit(current_drive, &fake_change) ||
2922 TESTF(FD_DISK_CHANGED)) {
2923 DPRINT("disk absent or changed during operation\n");
2924 REPEAT;
2925 }
2926 if (!_floppy) { /* Autodetection */
2927 if (!probing) {
2928 DRS->probed_format = 0;
2929 if (next_valid_format()) {
2930 DPRINT("no autodetectable formats\n");
2931 _floppy = NULL;
2932 REPEAT;
2933 }
2934 }
2935 probing = 1;
2936 _floppy =
2937 floppy_type + DP->autodetect[DRS->probed_format];
2938 } else
2939 probing = 0;
2940 errors = &(current_req->errors);
2941 tmp = make_raw_rw_request();
2942 if (tmp < 2) {
2943 request_done(tmp);
2944 continue;
2945 }
2946
2947 if (TESTF(FD_NEED_TWADDLE))
2948 twaddle();
2949 schedule_bh(floppy_start);
2950 debugt("queue fd request");
2951 return;
2952 }
2953#undef REPEAT
2954}
2955
2956static struct cont_t rw_cont = {
2957 .interrupt = rw_interrupt,
2958 .redo = redo_fd_request,
2959 .error = bad_flp_intr,
2960 .done = request_done
2961};
2962
2963static void process_fd_request(void)
2964{
2965 cont = &rw_cont;
2966 schedule_bh(redo_fd_request);
2967}
2968
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002969static void do_fd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970{
2971 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002972 pr_info("VFS: do_fd_request called on non-open device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 return;
2974 }
2975
2976 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002977 pr_info("warning: usage count=0, current_req=%p exiting\n",
2978 current_req);
2979 pr_info("sect=%ld type=%x flags=%x\n",
2980 (long)blk_rq_pos(current_req), current_req->cmd_type,
2981 current_req->cmd_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 return;
2983 }
2984 if (test_bit(0, &fdc_busy)) {
2985 /* fdc busy, this new request will be treated when the
2986 current one is done */
2987 is_alive("do fd request, old request running");
2988 return;
2989 }
2990 lock_fdc(MAXTIMEOUT, 0);
2991 process_fd_request();
2992 is_alive("do fd request");
2993}
2994
2995static struct cont_t poll_cont = {
2996 .interrupt = success_and_wakeup,
2997 .redo = floppy_ready,
2998 .error = generic_failure,
2999 .done = generic_done
3000};
3001
3002static int poll_drive(int interruptible, int flag)
3003{
3004 int ret;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003005
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 /* no auto-sense, just clear dcl */
3007 raw_cmd = &default_raw_cmd;
3008 raw_cmd->flags = flag;
3009 raw_cmd->track = 0;
3010 raw_cmd->cmd_count = 0;
3011 cont = &poll_cont;
Joe Perches87f530d2010-03-10 15:20:54 -08003012 debug_dcl(DP->flags, "setting NEWCHANGE in poll_drive\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 SETF(FD_DISK_NEWCHANGE);
3014 WAIT(floppy_ready);
3015 return ret;
3016}
3017
3018/*
3019 * User triggered reset
3020 * ====================
3021 */
3022
3023static void reset_intr(void)
3024{
Joe Perchesb46df352010-03-10 15:20:46 -08003025 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026}
3027
3028static struct cont_t reset_cont = {
3029 .interrupt = reset_intr,
3030 .redo = success_and_wakeup,
3031 .error = generic_failure,
3032 .done = generic_done
3033};
3034
3035static int user_reset_fdc(int drive, int arg, int interruptible)
3036{
3037 int ret;
3038
Joe Perches52a0d612010-03-10 15:20:53 -08003039 if (lock_fdc(drive, interruptible))
3040 return -EINTR;
3041
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 if (arg == FD_RESET_ALWAYS)
3043 FDCS->reset = 1;
3044 if (FDCS->reset) {
3045 cont = &reset_cont;
3046 WAIT(reset_fdc);
3047 }
3048 process_fd_request();
Joe Perches52a0d612010-03-10 15:20:53 -08003049 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050}
3051
3052/*
3053 * Misc Ioctl's and support
3054 * ========================
3055 */
3056static inline int fd_copyout(void __user *param, const void *address,
3057 unsigned long size)
3058{
3059 return copy_to_user(param, address, size) ? -EFAULT : 0;
3060}
3061
Joe Perches48c8cee2010-03-10 15:20:45 -08003062static inline int fd_copyin(void __user *param, void *address,
3063 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064{
3065 return copy_from_user(address, param, size) ? -EFAULT : 0;
3066}
3067
Joe Perches48c8cee2010-03-10 15:20:45 -08003068#define _COPYOUT(x) (copy_to_user((void __user *)param, &(x), sizeof(x)) \
3069 ? -EFAULT : 0)
3070#define _COPYIN(x) (copy_from_user(&(x), (void __user *)param, sizeof(x)) \
3071 ? -EFAULT : 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072
Joe Perches48c8cee2010-03-10 15:20:45 -08003073#define COPYOUT(x) ECALL(_COPYOUT(x))
3074#define COPYIN(x) ECALL(_COPYIN(x))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075
3076static inline const char *drive_name(int type, int drive)
3077{
3078 struct floppy_struct *floppy;
3079
3080 if (type)
3081 floppy = floppy_type + type;
3082 else {
3083 if (UDP->native_format)
3084 floppy = floppy_type + UDP->native_format;
3085 else
3086 return "(null)";
3087 }
3088 if (floppy->name)
3089 return floppy->name;
3090 else
3091 return "(null)";
3092}
3093
3094/* raw commands */
3095static void raw_cmd_done(int flag)
3096{
3097 int i;
3098
3099 if (!flag) {
3100 raw_cmd->flags |= FD_RAW_FAILURE;
3101 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3102 } else {
3103 raw_cmd->reply_count = inr;
3104 if (raw_cmd->reply_count > MAX_REPLIES)
3105 raw_cmd->reply_count = 0;
3106 for (i = 0; i < raw_cmd->reply_count; i++)
3107 raw_cmd->reply[i] = reply_buffer[i];
3108
3109 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3110 unsigned long flags;
3111 flags = claim_dma_lock();
3112 raw_cmd->length = fd_get_dma_residue();
3113 release_dma_lock(flags);
3114 }
3115
3116 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3117 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3118 raw_cmd->flags |= FD_RAW_FAILURE;
3119
3120 if (disk_change(current_drive))
3121 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3122 else
3123 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3124 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3125 motor_off_callback(current_drive);
3126
3127 if (raw_cmd->next &&
3128 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3129 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3130 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3131 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3132 raw_cmd = raw_cmd->next;
3133 return;
3134 }
3135 }
3136 generic_done(flag);
3137}
3138
3139static struct cont_t raw_cmd_cont = {
3140 .interrupt = success_and_wakeup,
3141 .redo = floppy_start,
3142 .error = generic_failure,
3143 .done = raw_cmd_done
3144};
3145
3146static inline int raw_cmd_copyout(int cmd, char __user *param,
3147 struct floppy_raw_cmd *ptr)
3148{
3149 int ret;
3150
3151 while (ptr) {
3152 COPYOUT(*ptr);
3153 param += sizeof(struct floppy_raw_cmd);
3154 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003155 if (ptr->length >= 0 &&
3156 ptr->length <= ptr->buffer_length) {
3157 long length = ptr->buffer_length - ptr->length;
3158 ECALL(fd_copyout(ptr->data, ptr->kernel_data,
3159 length));
3160 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 }
3162 ptr = ptr->next;
3163 }
3164 return 0;
3165}
3166
3167static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3168{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003169 struct floppy_raw_cmd *next;
3170 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171
3172 this = *ptr;
3173 *ptr = NULL;
3174 while (this) {
3175 if (this->buffer_length) {
3176 fd_dma_mem_free((unsigned long)this->kernel_data,
3177 this->buffer_length);
3178 this->buffer_length = 0;
3179 }
3180 next = this->next;
3181 kfree(this);
3182 this = next;
3183 }
3184}
3185
3186static inline int raw_cmd_copyin(int cmd, char __user *param,
3187 struct floppy_raw_cmd **rcmd)
3188{
3189 struct floppy_raw_cmd *ptr;
3190 int ret;
3191 int i;
3192
3193 *rcmd = NULL;
3194 while (1) {
3195 ptr = (struct floppy_raw_cmd *)
3196 kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3197 if (!ptr)
3198 return -ENOMEM;
3199 *rcmd = ptr;
3200 COPYIN(*ptr);
3201 ptr->next = NULL;
3202 ptr->buffer_length = 0;
3203 param += sizeof(struct floppy_raw_cmd);
3204 if (ptr->cmd_count > 33)
3205 /* the command may now also take up the space
3206 * initially intended for the reply & the
3207 * reply count. Needed for long 82078 commands
3208 * such as RESTORE, which takes ... 17 command
3209 * bytes. Murphy's law #137: When you reserve
3210 * 16 bytes for a structure, you'll one day
3211 * discover that you really need 17...
3212 */
3213 return -EINVAL;
3214
3215 for (i = 0; i < 16; i++)
3216 ptr->reply[i] = 0;
3217 ptr->resultcode = 0;
3218 ptr->kernel_data = NULL;
3219
3220 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3221 if (ptr->length <= 0)
3222 return -EINVAL;
3223 ptr->kernel_data =
3224 (char *)fd_dma_mem_alloc(ptr->length);
3225 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3226 if (!ptr->kernel_data)
3227 return -ENOMEM;
3228 ptr->buffer_length = ptr->length;
3229 }
3230 if (ptr->flags & FD_RAW_WRITE)
3231 ECALL(fd_copyin(ptr->data, ptr->kernel_data,
3232 ptr->length));
3233 rcmd = &(ptr->next);
3234 if (!(ptr->flags & FD_RAW_MORE))
3235 return 0;
3236 ptr->rate &= 0x43;
3237 }
3238}
3239
3240static int raw_cmd_ioctl(int cmd, void __user *param)
3241{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003243 int drive;
3244 int ret2;
3245 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246
3247 if (FDCS->rawcmd <= 1)
3248 FDCS->rawcmd = 1;
3249 for (drive = 0; drive < N_DRIVE; drive++) {
3250 if (FDC(drive) != fdc)
3251 continue;
3252 if (drive == current_drive) {
3253 if (UDRS->fd_ref > 1) {
3254 FDCS->rawcmd = 2;
3255 break;
3256 }
3257 } else if (UDRS->fd_ref) {
3258 FDCS->rawcmd = 2;
3259 break;
3260 }
3261 }
3262
3263 if (FDCS->reset)
3264 return -EIO;
3265
3266 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3267 if (ret) {
3268 raw_cmd_free(&my_raw_cmd);
3269 return ret;
3270 }
3271
3272 raw_cmd = my_raw_cmd;
3273 cont = &raw_cmd_cont;
3274 ret = wait_til_done(floppy_start, 1);
Joe Perches87f530d2010-03-10 15:20:54 -08003275 debug_dcl(DP->flags, "calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276
3277 if (ret != -EINTR && FDCS->reset)
3278 ret = -EIO;
3279
3280 DRS->track = NO_TRACK;
3281
3282 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3283 if (!ret)
3284 ret = ret2;
3285 raw_cmd_free(&my_raw_cmd);
3286 return ret;
3287}
3288
3289static int invalidate_drive(struct block_device *bdev)
3290{
3291 /* invalidate the buffer track to force a reread */
3292 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3293 process_fd_request();
3294 check_disk_change(bdev);
3295 return 0;
3296}
3297
3298static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
3299 int drive, int type, struct block_device *bdev)
3300{
3301 int cnt;
3302
3303 /* sanity checking for parameters. */
3304 if (g->sect <= 0 ||
3305 g->head <= 0 ||
3306 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3307 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003308 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 return -EINVAL;
3310 if (type) {
3311 if (!capable(CAP_SYS_ADMIN))
3312 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003313 mutex_lock(&open_lock);
Jiri Slaby8516a502009-06-30 11:41:44 -07003314 if (lock_fdc(drive, 1)) {
3315 mutex_unlock(&open_lock);
3316 return -EINTR;
3317 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 floppy_type[type] = *g;
3319 floppy_type[type].name = "user format";
3320 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3321 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3322 floppy_type[type].size + 1;
3323 process_fd_request();
3324 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3325 struct block_device *bdev = opened_bdev[cnt];
3326 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3327 continue;
Christoph Hellwig2ef41632005-05-05 16:15:59 -07003328 __invalidate_device(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003330 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 } else {
3332 int oldStretch;
Joe Perches52a0d612010-03-10 15:20:53 -08003333
3334 if (lock_fdc(drive, 1))
3335 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 if (cmd != FDDEFPRM)
3337 /* notice a disk change immediately, else
3338 * we lose our settings immediately*/
3339 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3340 oldStretch = g->stretch;
3341 user_params[drive] = *g;
3342 if (buffer_drive == drive)
3343 SUPBOUND(buffer_max, user_params[drive].sect);
3344 current_type[drive] = &user_params[drive];
3345 floppy_sizes[drive] = user_params[drive].size;
3346 if (cmd == FDDEFPRM)
3347 DRS->keep_data = -1;
3348 else
3349 DRS->keep_data = 1;
3350 /* invalidation. Invalidate only when needed, i.e.
3351 * when there are already sectors in the buffer cache
3352 * whose number will change. This is useful, because
3353 * mtools often changes the geometry of the disk after
3354 * looking at the boot block */
3355 if (DRS->maxblock > user_params[drive].sect ||
3356 DRS->maxtrack ||
3357 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003358 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 invalidate_drive(bdev);
3360 else
3361 process_fd_request();
3362 }
3363 return 0;
3364}
3365
3366/* handle obsolete ioctl's */
3367static int ioctl_table[] = {
3368 FDCLRPRM,
3369 FDSETPRM,
3370 FDDEFPRM,
3371 FDGETPRM,
3372 FDMSGON,
3373 FDMSGOFF,
3374 FDFMTBEG,
3375 FDFMTTRK,
3376 FDFMTEND,
3377 FDSETEMSGTRESH,
3378 FDFLUSH,
3379 FDSETMAXERRS,
3380 FDGETMAXERRS,
3381 FDGETDRVTYP,
3382 FDSETDRVPRM,
3383 FDGETDRVPRM,
3384 FDGETDRVSTAT,
3385 FDPOLLDRVSTAT,
3386 FDRESET,
3387 FDGETFDCSTAT,
3388 FDWERRORCLR,
3389 FDWERRORGET,
3390 FDRAWCMD,
3391 FDEJECT,
3392 FDTWADDLE
3393};
3394
3395static inline int normalize_ioctl(int *cmd, int *size)
3396{
3397 int i;
3398
3399 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3400 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3401 *size = _IOC_SIZE(*cmd);
3402 *cmd = ioctl_table[i];
3403 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003404 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 return -EFAULT;
3406 }
3407 return 0;
3408 }
3409 }
3410 return -EINVAL;
3411}
3412
3413static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3414{
3415 if (type)
3416 *g = &floppy_type[type];
3417 else {
Joe Perches52a0d612010-03-10 15:20:53 -08003418 if (lock_fdc(drive, 0))
3419 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 CALL(poll_drive(0, 0));
3421 process_fd_request();
3422 *g = current_type[drive];
3423 }
3424 if (!*g)
3425 return -ENODEV;
3426 return 0;
3427}
3428
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003429static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3430{
3431 int drive = (long)bdev->bd_disk->private_data;
3432 int type = ITYPE(drive_state[drive].fd_device);
3433 struct floppy_struct *g;
3434 int ret;
3435
3436 ret = get_floppy_geometry(drive, type, &g);
3437 if (ret)
3438 return ret;
3439
3440 geo->heads = g->head;
3441 geo->sectors = g->sect;
3442 geo->cylinders = g->track;
3443 return 0;
3444}
3445
Al Viroa4af9b42008-03-02 09:27:55 -05003446static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447 unsigned long param)
3448{
Al Viroa4af9b42008-03-02 09:27:55 -05003449#define FD_IOCTL_ALLOWED (mode & (FMODE_WRITE|FMODE_WRITE_IOCTL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450
Al Viroa4af9b42008-03-02 09:27:55 -05003451 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003452 int type = ITYPE(UDRS->fd_device);
3453 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 int ret;
3455 int size;
3456 union inparam {
3457 struct floppy_struct g; /* geometry */
3458 struct format_descr f;
3459 struct floppy_max_errors max_errors;
3460 struct floppy_drive_params dp;
3461 } inparam; /* parameters coming from user space */
3462 const char *outparam; /* parameters passed back to user space */
3463
3464 /* convert compatibility eject ioctls into floppy eject ioctl.
3465 * We do this in order to provide a means to eject floppy disks before
3466 * installing the new fdutils package */
3467 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003468 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 DPRINT("obsolete eject ioctl\n");
3470 DPRINT("please use floppycontrol --eject\n");
3471 cmd = FDEJECT;
3472 }
3473
Joe Perchesa81ee542010-03-10 15:20:46 -08003474 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 return -EINVAL;
3476
Joe Perchesa81ee542010-03-10 15:20:46 -08003477 /* convert the old style command into a new style command */
3478 ECALL(normalize_ioctl(&cmd, &size));
3479
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480 /* permission checks */
3481 if (((cmd & 0x40) && !FD_IOCTL_ALLOWED) ||
3482 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3483 return -EPERM;
3484
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003485 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3486 return -EINVAL;
3487
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 /* copyin */
Joe Perchesb87c9e02010-03-10 15:20:50 -08003489 memset(&inparam, 0, sizeof(inparam));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 if (_IOC_DIR(cmd) & _IOC_WRITE)
Joe Perchesda273652010-03-10 15:20:52 -08003491 ECALL(fd_copyin((void __user *)param, &inparam, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492
Joe Perchesda273652010-03-10 15:20:52 -08003493 switch (cmd) {
3494 case FDEJECT:
3495 if (UDRS->fd_ref != 1)
3496 /* somebody else has this drive open */
3497 return -EBUSY;
Joe Perches52a0d612010-03-10 15:20:53 -08003498 if (lock_fdc(drive, 1))
3499 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500
Joe Perchesda273652010-03-10 15:20:52 -08003501 /* do the actual eject. Fails on
3502 * non-Sparc architectures */
3503 ret = fd_eject(UNIT(drive));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504
Joe Perchesda273652010-03-10 15:20:52 -08003505 USETF(FD_DISK_CHANGED);
3506 USETF(FD_VERIFY);
3507 process_fd_request();
3508 return ret;
3509 case FDCLRPRM:
Joe Perches52a0d612010-03-10 15:20:53 -08003510 if (lock_fdc(drive, 1))
3511 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003512 current_type[drive] = NULL;
3513 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3514 UDRS->keep_data = 0;
3515 return invalidate_drive(bdev);
3516 case FDSETPRM:
3517 case FDDEFPRM:
3518 return set_geometry(cmd, &inparam.g, drive, type, bdev);
3519 case FDGETPRM:
3520 ECALL(get_floppy_geometry(drive, type,
3521 (struct floppy_struct **)
3522 &outparam));
3523 break;
3524 case FDMSGON:
3525 UDP->flags |= FTD_MSG;
3526 return 0;
3527 case FDMSGOFF:
3528 UDP->flags &= ~FTD_MSG;
3529 return 0;
3530 case FDFMTBEG:
Joe Perches52a0d612010-03-10 15:20:53 -08003531 if (lock_fdc(drive, 1))
3532 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003533 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3534 ret = UDRS->flags;
3535 process_fd_request();
3536 if (ret & FD_VERIFY)
3537 return -ENODEV;
3538 if (!(ret & FD_DISK_WRITABLE))
3539 return -EROFS;
3540 return 0;
3541 case FDFMTTRK:
3542 if (UDRS->fd_ref != 1)
3543 return -EBUSY;
3544 return do_format(drive, &inparam.f);
3545 case FDFMTEND:
3546 case FDFLUSH:
Joe Perches52a0d612010-03-10 15:20:53 -08003547 if (lock_fdc(drive, 1))
3548 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003549 return invalidate_drive(bdev);
3550 case FDSETEMSGTRESH:
3551 UDP->max_errors.reporting = (unsigned short)(param & 0x0f);
3552 return 0;
3553 case FDGETMAXERRS:
3554 outparam = (const char *)&UDP->max_errors;
3555 break;
3556 case FDSETMAXERRS:
3557 UDP->max_errors = inparam.max_errors;
3558 break;
3559 case FDGETDRVTYP:
3560 outparam = drive_name(type, drive);
3561 SUPBOUND(size, strlen(outparam) + 1);
3562 break;
3563 case FDSETDRVPRM:
3564 *UDP = inparam.dp;
3565 break;
3566 case FDGETDRVPRM:
3567 outparam = (const char *)UDP;
3568 break;
3569 case FDPOLLDRVSTAT:
Joe Perches52a0d612010-03-10 15:20:53 -08003570 if (lock_fdc(drive, 1))
3571 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003572 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3573 process_fd_request();
3574 /* fall through */
3575 case FDGETDRVSTAT:
3576 outparam = (const char *)UDRS;
3577 break;
3578 case FDRESET:
3579 return user_reset_fdc(drive, (int)param, 1);
3580 case FDGETFDCSTAT:
3581 outparam = (const char *)UFDCS;
3582 break;
3583 case FDWERRORCLR:
3584 memset(UDRWE, 0, sizeof(*UDRWE));
3585 return 0;
3586 case FDWERRORGET:
3587 outparam = (const char *)UDRWE;
3588 break;
3589 case FDRAWCMD:
3590 if (type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 return -EINVAL;
Joe Perches52a0d612010-03-10 15:20:53 -08003592 if (lock_fdc(drive, 1))
3593 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003594 set_floppy(drive);
3595 CALL(i = raw_cmd_ioctl(cmd, (void __user *)param));
3596 process_fd_request();
3597 return i;
3598 case FDTWADDLE:
Joe Perches52a0d612010-03-10 15:20:53 -08003599 if (lock_fdc(drive, 1))
3600 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003601 twaddle();
3602 process_fd_request();
3603 return 0;
3604 default:
3605 return -EINVAL;
3606 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607
3608 if (_IOC_DIR(cmd) & _IOC_READ)
3609 return fd_copyout((void __user *)param, outparam, size);
Joe Perchesda273652010-03-10 15:20:52 -08003610
3611 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612}
3613
3614static void __init config_types(void)
3615{
Joe Perchesb46df352010-03-10 15:20:46 -08003616 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 int drive;
3618
3619 /* read drive info out of physical CMOS */
3620 drive = 0;
3621 if (!UDP->cmos)
3622 UDP->cmos = FLOPPY0_TYPE;
3623 drive = 1;
3624 if (!UDP->cmos && FLOPPY1_TYPE)
3625 UDP->cmos = FLOPPY1_TYPE;
3626
Jesper Juhl06f748c2007-10-16 23:30:57 -07003627 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628
3629 for (drive = 0; drive < N_DRIVE; drive++) {
3630 unsigned int type = UDP->cmos;
3631 struct floppy_drive_params *params;
3632 const char *name = NULL;
3633 static char temparea[32];
3634
Tobias Klauser945f3902006-01-08 01:05:11 -08003635 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 params = &default_drive_params[type].params;
3637 if (type) {
3638 name = default_drive_params[type].name;
3639 allowed_drive_mask |= 1 << drive;
3640 } else
3641 allowed_drive_mask &= ~(1 << drive);
3642 } else {
3643 params = &default_drive_params[0].params;
3644 sprintf(temparea, "unknown type %d (usb?)", type);
3645 name = temparea;
3646 }
3647 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003648 const char *prepend;
3649 if (!has_drive) {
3650 prepend = "";
3651 has_drive = true;
3652 pr_info("Floppy drive(s):");
3653 } else {
3654 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655 }
Joe Perchesb46df352010-03-10 15:20:46 -08003656
3657 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658 }
3659 *UDP = *params;
3660 }
Joe Perchesb46df352010-03-10 15:20:46 -08003661
3662 if (has_drive)
3663 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664}
3665
Al Viroa4af9b42008-03-02 09:27:55 -05003666static int floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667{
Al Viroa4af9b42008-03-02 09:27:55 -05003668 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003670 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671 if (UDRS->fd_ref < 0)
3672 UDRS->fd_ref = 0;
3673 else if (!UDRS->fd_ref--) {
3674 DPRINT("floppy_release with fd_ref == 0");
3675 UDRS->fd_ref = 0;
3676 }
3677 if (!UDRS->fd_ref)
3678 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003679 mutex_unlock(&open_lock);
Ingo Molnar3e541a42006-07-03 00:24:23 -07003680
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681 return 0;
3682}
3683
3684/*
3685 * floppy_open check for aliasing (/dev/fd0 can be the same as
3686 * /dev/PS0 etc), and disallows simultaneous access to the same
3687 * drive with different device numbers.
3688 */
Al Viroa4af9b42008-03-02 09:27:55 -05003689static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690{
Al Viroa4af9b42008-03-02 09:27:55 -05003691 int drive = (long)bdev->bd_disk->private_data;
3692 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 int try;
3694 int res = -EBUSY;
3695 char *tmp;
3696
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003697 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003699 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 goto out2;
3701
3702 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
3703 USETF(FD_DISK_CHANGED);
3704 USETF(FD_VERIFY);
3705 }
3706
Al Viroa4af9b42008-03-02 09:27:55 -05003707 if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 goto out2;
3709
Al Viroa4af9b42008-03-02 09:27:55 -05003710 if (mode & FMODE_EXCL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 UDRS->fd_ref = -1;
3712 else
3713 UDRS->fd_ref++;
3714
Al Viroa4af9b42008-03-02 09:27:55 -05003715 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716
3717 res = -ENXIO;
3718
3719 if (!floppy_track_buffer) {
3720 /* if opening an ED drive, reserve a big buffer,
3721 * else reserve a small one */
3722 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3723 try = 64; /* Only 48 actually useful */
3724 else
3725 try = 32; /* Only 24 actually useful */
3726
3727 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3728 if (!tmp && !floppy_track_buffer) {
3729 try >>= 1; /* buffer only one side */
3730 INFBOUND(try, 16);
3731 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3732 }
Joe Perchesa81ee542010-03-10 15:20:46 -08003733 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 if (!tmp && !floppy_track_buffer) {
3736 DPRINT("Unable to allocate DMA memory\n");
3737 goto out;
3738 }
3739 if (floppy_track_buffer) {
3740 if (tmp)
3741 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3742 } else {
3743 buffer_min = buffer_max = -1;
3744 floppy_track_buffer = tmp;
3745 max_buffer_sectors = try;
3746 }
3747 }
3748
Al Viroa4af9b42008-03-02 09:27:55 -05003749 new_dev = MINOR(bdev->bd_dev);
3750 UDRS->fd_device = new_dev;
3751 set_capacity(disks[drive], floppy_sizes[new_dev]);
3752 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753 if (buffer_drive == drive)
3754 buffer_track = -1;
3755 }
3756
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 if (UFDCS->rawcmd == 1)
3758 UFDCS->rawcmd = 2;
3759
Al Viroa4af9b42008-03-02 09:27:55 -05003760 if (!(mode & FMODE_NDELAY)) {
3761 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762 UDRS->last_checked = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003763 check_disk_change(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764 if (UTESTF(FD_DISK_CHANGED))
3765 goto out;
3766 }
3767 res = -EROFS;
Al Viroa4af9b42008-03-02 09:27:55 -05003768 if ((mode & FMODE_WRITE) && !(UTESTF(FD_DISK_WRITABLE)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769 goto out;
3770 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003771 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772 return 0;
3773out:
3774 if (UDRS->fd_ref < 0)
3775 UDRS->fd_ref = 0;
3776 else
3777 UDRS->fd_ref--;
3778 if (!UDRS->fd_ref)
3779 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003781 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782 return res;
3783}
3784
3785/*
3786 * Check if the disk has been changed or if a change has been faked.
3787 */
3788static int check_floppy_change(struct gendisk *disk)
3789{
3790 int drive = (long)disk->private_data;
3791
3792 if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY))
3793 return 1;
3794
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003795 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796 lock_fdc(drive, 0);
3797 poll_drive(0, 0);
3798 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 }
3800
3801 if (UTESTF(FD_DISK_CHANGED) ||
3802 UTESTF(FD_VERIFY) ||
3803 test_bit(drive, &fake_change) ||
3804 (!ITYPE(UDRS->fd_device) && !current_type[drive]))
3805 return 1;
3806 return 0;
3807}
3808
3809/*
3810 * This implements "read block 0" for floppy_revalidate().
3811 * Needed for format autodetection, checking whether there is
3812 * a disk in the drive, and whether that disk is writable.
3813 */
3814
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003815static void floppy_rb0_complete(struct bio *bio, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 complete((struct completion *)bio->bi_private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818}
3819
3820static int __floppy_read_block_0(struct block_device *bdev)
3821{
3822 struct bio bio;
3823 struct bio_vec bio_vec;
3824 struct completion complete;
3825 struct page *page;
3826 size_t size;
3827
3828 page = alloc_page(GFP_NOIO);
3829 if (!page) {
3830 process_fd_request();
3831 return -ENOMEM;
3832 }
3833
3834 size = bdev->bd_block_size;
3835 if (!size)
3836 size = 1024;
3837
3838 bio_init(&bio);
3839 bio.bi_io_vec = &bio_vec;
3840 bio_vec.bv_page = page;
3841 bio_vec.bv_len = size;
3842 bio_vec.bv_offset = 0;
3843 bio.bi_vcnt = 1;
3844 bio.bi_idx = 0;
3845 bio.bi_size = size;
3846 bio.bi_bdev = bdev;
3847 bio.bi_sector = 0;
3848 init_completion(&complete);
3849 bio.bi_private = &complete;
3850 bio.bi_end_io = floppy_rb0_complete;
3851
3852 submit_bio(READ, &bio);
3853 generic_unplug_device(bdev_get_queue(bdev));
3854 process_fd_request();
3855 wait_for_completion(&complete);
3856
3857 __free_page(page);
3858
3859 return 0;
3860}
3861
3862/* revalidate the floppy disk, i.e. trigger format autodetection by reading
3863 * the bootblock (block 0). "Autodetection" is also needed to check whether
3864 * there is a disk in the drive at all... Thus we also do it for fixed
3865 * geometry formats */
3866static int floppy_revalidate(struct gendisk *disk)
3867{
3868 int drive = (long)disk->private_data;
3869#define NO_GEOM (!current_type[drive] && !ITYPE(UDRS->fd_device))
3870 int cf;
3871 int res = 0;
3872
3873 if (UTESTF(FD_DISK_CHANGED) ||
3874 UTESTF(FD_VERIFY) || test_bit(drive, &fake_change) || NO_GEOM) {
3875 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08003876 pr_info("VFS: revalidate called on non-open device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 return -EFAULT;
3878 }
3879 lock_fdc(drive, 0);
3880 cf = UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY);
3881 if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)) {
3882 process_fd_request(); /*already done by another thread */
3883 return 0;
3884 }
3885 UDRS->maxblock = 0;
3886 UDRS->maxtrack = 0;
3887 if (buffer_drive == drive)
3888 buffer_track = -1;
3889 clear_bit(drive, &fake_change);
3890 UCLEARF(FD_DISK_CHANGED);
3891 if (cf)
3892 UDRS->generation++;
3893 if (NO_GEOM) {
3894 /* auto-sensing */
3895 res = __floppy_read_block_0(opened_bdev[drive]);
3896 } else {
3897 if (cf)
3898 poll_drive(0, FD_RAW_NEED_DISK);
3899 process_fd_request();
3900 }
3901 }
3902 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
3903 return res;
3904}
3905
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07003906static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07003907 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05003908 .open = floppy_open,
3909 .release = floppy_release,
3910 .locked_ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003911 .getgeo = fd_getgeo,
3912 .media_changed = check_floppy_change,
3913 .revalidate_disk = floppy_revalidate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916/*
3917 * Floppy Driver initialization
3918 * =============================
3919 */
3920
3921/* Determine the floppy disk controller type */
3922/* This routine was written by David C. Niemi */
3923static char __init get_fdc_version(void)
3924{
3925 int r;
3926
3927 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
3928 if (FDCS->reset)
3929 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003930 r = result();
3931 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932 return FDC_NONE; /* No FDC present ??? */
3933 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003934 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3936 }
3937 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003938 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3939 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940 return FDC_UNKNOWN;
3941 }
3942
3943 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003944 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003945 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3946 }
3947
3948 output_byte(FD_PERPENDICULAR);
3949 if (need_more_output() == MORE_OUTPUT) {
3950 output_byte(0);
3951 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003952 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 return FDC_82072A; /* 82072A as found on Sparcs. */
3954 }
3955
3956 output_byte(FD_UNLOCK);
3957 r = result();
3958 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003959 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003960 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 * LOCK/UNLOCK */
3962 }
3963 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003964 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3965 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 return FDC_UNKNOWN;
3967 }
3968 output_byte(FD_PARTID);
3969 r = result();
3970 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003971 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3972 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973 return FDC_UNKNOWN;
3974 }
3975 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003976 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 return FDC_82077; /* Revised 82077AA passes all the tests */
3978 }
3979 switch (reply_buffer[0] >> 5) {
3980 case 0x0:
3981 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08003982 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 return FDC_82078;
3984 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08003985 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986 return FDC_82078;
3987 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08003988 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 return FDC_S82078B;
3990 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08003991 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992 return FDC_87306;
3993 default:
Joe Perchesb46df352010-03-10 15:20:46 -08003994 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
3995 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 return FDC_82078_UNKN;
3997 }
3998} /* get_fdc_version */
3999
4000/* lilo configuration */
4001
4002static void __init floppy_set_flags(int *ints, int param, int param2)
4003{
4004 int i;
4005
4006 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4007 if (param)
4008 default_drive_params[i].params.flags |= param2;
4009 else
4010 default_drive_params[i].params.flags &= ~param2;
4011 }
4012 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
4013}
4014
4015static void __init daring(int *ints, int param, int param2)
4016{
4017 int i;
4018
4019 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4020 if (param) {
4021 default_drive_params[i].params.select_delay = 0;
4022 default_drive_params[i].params.flags |=
4023 FD_SILENT_DCL_CLEAR;
4024 } else {
4025 default_drive_params[i].params.select_delay =
4026 2 * HZ / 100;
4027 default_drive_params[i].params.flags &=
4028 ~FD_SILENT_DCL_CLEAR;
4029 }
4030 }
4031 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
4032}
4033
4034static void __init set_cmos(int *ints, int dummy, int dummy2)
4035{
4036 int current_drive = 0;
4037
4038 if (ints[0] != 2) {
4039 DPRINT("wrong number of parameters for CMOS\n");
4040 return;
4041 }
4042 current_drive = ints[1];
4043 if (current_drive < 0 || current_drive >= 8) {
4044 DPRINT("bad drive for set_cmos\n");
4045 return;
4046 }
4047#if N_FDC > 1
4048 if (current_drive >= 4 && !FDC2)
4049 FDC2 = 0x370;
4050#endif
4051 DP->cmos = ints[2];
4052 DPRINT("setting CMOS code to %d\n", ints[2]);
4053}
4054
4055static struct param_table {
4056 const char *name;
4057 void (*fn) (int *ints, int param, int param2);
4058 int *var;
4059 int def_param;
4060 int param2;
4061} config_params[] __initdata = {
4062 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4063 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4064 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4065 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4066 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4067 {"daring", daring, NULL, 1, 0},
4068#if N_FDC > 1
4069 {"two_fdc", NULL, &FDC2, 0x370, 0},
4070 {"one_fdc", NULL, &FDC2, 0, 0},
4071#endif
4072 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4073 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4074 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4075 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4076 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4077 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4078 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4079 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4080 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4081 {"nofifo", NULL, &no_fifo, 0x20, 0},
4082 {"usefifo", NULL, &no_fifo, 0, 0},
4083 {"cmos", set_cmos, NULL, 0, 0},
4084 {"slow", NULL, &slow_floppy, 1, 0},
4085 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4086 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4087 {"L40SX", NULL, &print_unex, 0, 0}
4088
4089 EXTRA_FLOPPY_PARAMS
4090};
4091
4092static int __init floppy_setup(char *str)
4093{
4094 int i;
4095 int param;
4096 int ints[11];
4097
4098 str = get_options(str, ARRAY_SIZE(ints), ints);
4099 if (str) {
4100 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4101 if (strcmp(str, config_params[i].name) == 0) {
4102 if (ints[0])
4103 param = ints[1];
4104 else
4105 param = config_params[i].def_param;
4106 if (config_params[i].fn)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004107 config_params[i].fn(ints, param,
4108 config_params[i].
4109 param2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110 if (config_params[i].var) {
4111 DPRINT("%s=%d\n", str, param);
4112 *config_params[i].var = param;
4113 }
4114 return 1;
4115 }
4116 }
4117 }
4118 if (str) {
4119 DPRINT("unknown floppy option [%s]\n", str);
4120
4121 DPRINT("allowed options are:");
4122 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004123 pr_cont(" %s", config_params[i].name);
4124 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125 } else
4126 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004127 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128 return 0;
4129}
4130
4131static int have_no_fdc = -ENODEV;
4132
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004133static ssize_t floppy_cmos_show(struct device *dev,
4134 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004135{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004136 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004137 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004138
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004139 drive = p->id;
4140 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004141}
Joe Perches48c8cee2010-03-10 15:20:45 -08004142
4143DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004144
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145static void floppy_device_release(struct device *dev)
4146{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147}
4148
Frans Popc90cd332009-07-25 22:24:54 +02004149static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004150{
4151 int fdc;
4152
4153 for (fdc = 0; fdc < N_FDC; fdc++)
4154 if (FDCS->address != -1)
4155 user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
4156
4157 return 0;
4158}
4159
Alexey Dobriyan47145212009-12-14 18:00:08 -08004160static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004161 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004162 .restore = floppy_resume,
4163};
4164
4165static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004166 .driver = {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004167 .name = "floppy",
4168 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004169 },
4170};
4171
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004172static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173
4174static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4175{
4176 int drive = (*part & 3) | ((*part & 0x80) >> 5);
4177 if (drive >= N_DRIVE ||
4178 !(allowed_drive_mask & (1 << drive)) ||
4179 fdc_state[FDC(drive)].version == FDC_NONE)
4180 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004181 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182 return NULL;
4183 *part = 0;
4184 return get_disk(disks[drive]);
4185}
4186
4187static int __init floppy_init(void)
4188{
4189 int i, unit, drive;
4190 int err, dr;
4191
Kumar Gala68e1ee62008-09-22 14:41:31 -07004192#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004193 if (check_legacy_ioport(FDC1))
4194 return -ENODEV;
4195#endif
4196
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197 raw_cmd = NULL;
4198
4199 for (dr = 0; dr < N_DRIVE; dr++) {
4200 disks[dr] = alloc_disk(1);
4201 if (!disks[dr]) {
4202 err = -ENOMEM;
4203 goto out_put_disk;
4204 }
4205
4206 disks[dr]->major = FLOPPY_MAJOR;
4207 disks[dr]->first_minor = TOMINOR(dr);
4208 disks[dr]->fops = &floppy_fops;
4209 sprintf(disks[dr]->disk_name, "fd%d", dr);
4210
4211 init_timer(&motor_off_timer[dr]);
4212 motor_off_timer[dr].data = dr;
4213 motor_off_timer[dr].function = motor_off_callback;
4214 }
4215
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216 err = register_blkdev(FLOPPY_MAJOR, "fd");
4217 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004218 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004220 err = platform_driver_register(&floppy_driver);
4221 if (err)
4222 goto out_unreg_blkdev;
4223
Linus Torvalds1da177e2005-04-16 15:20:36 -07004224 floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
4225 if (!floppy_queue) {
4226 err = -ENOMEM;
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004227 goto out_unreg_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228 }
Martin K. Petersen086fa5f2010-02-26 00:20:38 -05004229 blk_queue_max_hw_sectors(floppy_queue, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230
4231 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4232 floppy_find, NULL, NULL);
4233
4234 for (i = 0; i < 256; i++)
4235 if (ITYPE(i))
4236 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4237 else
4238 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4239
4240 reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
4241 config_types();
4242
4243 for (i = 0; i < N_FDC; i++) {
4244 fdc = i;
Joe Perchesb87c9e02010-03-10 15:20:50 -08004245 memset(FDCS, 0, sizeof(*FDCS));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246 FDCS->dtr = -1;
4247 FDCS->dor = 0x4;
4248#if defined(__sparc__) || defined(__mc68000__)
Joe Perches96534f12010-03-10 15:20:51 -08004249 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250#ifdef __mc68000__
4251 if (MACH_IS_SUN3X)
4252#endif
4253 FDCS->version = FDC_82072A;
4254#endif
4255 }
4256
4257 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 fdc_state[0].address = FDC1;
4259 if (fdc_state[0].address == -1) {
4260 del_timer(&fd_timeout);
4261 err = -ENODEV;
4262 goto out_unreg_region;
4263 }
4264#if N_FDC > 1
4265 fdc_state[1].address = FDC2;
4266#endif
4267
4268 fdc = 0; /* reset fdc in case of unexpected interrupt */
4269 err = floppy_grab_irq_and_dma();
4270 if (err) {
4271 del_timer(&fd_timeout);
4272 err = -EBUSY;
4273 goto out_unreg_region;
4274 }
4275
4276 /* initialise drive state */
4277 for (drive = 0; drive < N_DRIVE; drive++) {
Joe Perchesb87c9e02010-03-10 15:20:50 -08004278 memset(UDRS, 0, sizeof(*UDRS));
4279 memset(UDRWE, 0, sizeof(*UDRWE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280 USETF(FD_DISK_NEWCHANGE);
4281 USETF(FD_DISK_CHANGED);
4282 USETF(FD_VERIFY);
4283 UDRS->fd_device = -1;
4284 floppy_track_buffer = NULL;
4285 max_buffer_sectors = 0;
4286 }
4287 /*
4288 * Small 10 msec delay to let through any interrupt that
4289 * initialization might have triggered, to not
4290 * confuse detection:
4291 */
4292 msleep(10);
4293
4294 for (i = 0; i < N_FDC; i++) {
4295 fdc = i;
4296 FDCS->driver_version = FD_DRIVER_VERSION;
4297 for (unit = 0; unit < 4; unit++)
4298 FDCS->track[unit] = 0;
4299 if (FDCS->address == -1)
4300 continue;
4301 FDCS->rawcmd = 2;
4302 if (user_reset_fdc(-1, FD_RESET_ALWAYS, 0)) {
4303 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004304 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 FDCS->address = -1;
4306 FDCS->version = FDC_NONE;
4307 continue;
4308 }
4309 /* Try to determine the floppy controller type */
4310 FDCS->version = get_fdc_version();
4311 if (FDCS->version == FDC_NONE) {
4312 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004313 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314 FDCS->address = -1;
4315 continue;
4316 }
4317 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4318 can_use_virtual_dma = 0;
4319
4320 have_no_fdc = 0;
4321 /* Not all FDCs seem to be able to handle the version command
4322 * properly, so force a reset for the standard FDC clones,
4323 * to avoid interrupt garbage.
4324 */
4325 user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
4326 }
4327 fdc = 0;
4328 del_timer(&fd_timeout);
4329 current_drive = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 initialising = 0;
4331 if (have_no_fdc) {
4332 DPRINT("no floppy controllers found\n");
4333 err = have_no_fdc;
4334 goto out_flush_work;
4335 }
4336
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337 for (drive = 0; drive < N_DRIVE; drive++) {
4338 if (!(allowed_drive_mask & (1 << drive)))
4339 continue;
4340 if (fdc_state[FDC(drive)].version == FDC_NONE)
4341 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004342
4343 floppy_device[drive].name = floppy_device_name;
4344 floppy_device[drive].id = drive;
4345 floppy_device[drive].dev.release = floppy_device_release;
4346
4347 err = platform_device_register(&floppy_device[drive]);
4348 if (err)
4349 goto out_flush_work;
4350
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004351 err = device_create_file(&floppy_device[drive].dev,
4352 &dev_attr_cmos);
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004353 if (err)
4354 goto out_unreg_platform_dev;
4355
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356 /* to be cleaned up... */
4357 disks[drive]->private_data = (void *)(long)drive;
4358 disks[drive]->queue = floppy_queue;
4359 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004360 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 add_disk(disks[drive]);
4362 }
4363
4364 return 0;
4365
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004366out_unreg_platform_dev:
4367 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368out_flush_work:
4369 flush_scheduled_work();
4370 if (usage_count)
4371 floppy_release_irq_and_dma();
4372out_unreg_region:
4373 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4374 blk_cleanup_queue(floppy_queue);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004375out_unreg_driver:
4376 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377out_unreg_blkdev:
4378 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379out_put_disk:
4380 while (dr--) {
4381 del_timer(&motor_off_timer[dr]);
4382 put_disk(disks[dr]);
4383 }
4384 return err;
4385}
4386
4387static DEFINE_SPINLOCK(floppy_usage_lock);
4388
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004389static const struct io_region {
4390 int offset;
4391 int size;
4392} io_regions[] = {
4393 { 2, 1 },
4394 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4395 { 4, 2 },
4396 /* address + 6 is reserved, and may be taken by IDE.
4397 * Unfortunately, Adaptec doesn't know this :-(, */
4398 { 7, 1 },
4399};
4400
4401static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4402{
4403 while (p != io_regions) {
4404 p--;
4405 release_region(FDCS->address + p->offset, p->size);
4406 }
4407}
4408
4409#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4410
4411static int floppy_request_regions(int fdc)
4412{
4413 const struct io_region *p;
4414
4415 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004416 if (!request_region(FDCS->address + p->offset,
4417 p->size, "floppy")) {
4418 DPRINT("Floppy io-port 0x%04lx in use\n",
4419 FDCS->address + p->offset);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004420 floppy_release_allocated_regions(fdc, p);
4421 return -EBUSY;
4422 }
4423 }
4424 return 0;
4425}
4426
4427static void floppy_release_regions(int fdc)
4428{
4429 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4430}
4431
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432static int floppy_grab_irq_and_dma(void)
4433{
4434 unsigned long flags;
4435
4436 spin_lock_irqsave(&floppy_usage_lock, flags);
4437 if (usage_count++) {
4438 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4439 return 0;
4440 }
4441 spin_unlock_irqrestore(&floppy_usage_lock, flags);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004442
4443 /*
4444 * We might have scheduled a free_irq(), wait it to
4445 * drain first:
4446 */
4447 flush_scheduled_work();
4448
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449 if (fd_request_irq()) {
4450 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4451 FLOPPY_IRQ);
4452 spin_lock_irqsave(&floppy_usage_lock, flags);
4453 usage_count--;
4454 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4455 return -1;
4456 }
4457 if (fd_request_dma()) {
4458 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4459 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004460 if (can_use_virtual_dma & 2)
4461 use_virtual_dma = can_use_virtual_dma = 1;
4462 if (!(can_use_virtual_dma & 1)) {
4463 fd_free_irq();
4464 spin_lock_irqsave(&floppy_usage_lock, flags);
4465 usage_count--;
4466 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4467 return -1;
4468 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469 }
4470
4471 for (fdc = 0; fdc < N_FDC; fdc++) {
4472 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004473 if (floppy_request_regions(fdc))
4474 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 }
4476 }
4477 for (fdc = 0; fdc < N_FDC; fdc++) {
4478 if (FDCS->address != -1) {
4479 reset_fdc_info(1);
4480 fd_outb(FDCS->dor, FD_DOR);
4481 }
4482 }
4483 fdc = 0;
4484 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4485
4486 for (fdc = 0; fdc < N_FDC; fdc++)
4487 if (FDCS->address != -1)
4488 fd_outb(FDCS->dor, FD_DOR);
4489 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004490 * The driver will try and free resources and relies on us
4491 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 */
4493 fdc = 0;
4494 irqdma_allocated = 1;
4495 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004496cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497 fd_free_irq();
4498 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004499 while (--fdc >= 0)
4500 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 spin_lock_irqsave(&floppy_usage_lock, flags);
4502 usage_count--;
4503 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4504 return -1;
4505}
4506
4507static void floppy_release_irq_and_dma(void)
4508{
4509 int old_fdc;
4510#ifdef FLOPPY_SANITY_CHECK
4511#ifndef __sparc__
4512 int drive;
4513#endif
4514#endif
4515 long tmpsize;
4516 unsigned long tmpaddr;
4517 unsigned long flags;
4518
4519 spin_lock_irqsave(&floppy_usage_lock, flags);
4520 if (--usage_count) {
4521 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4522 return;
4523 }
4524 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4525 if (irqdma_allocated) {
4526 fd_disable_dma();
4527 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004528 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 irqdma_allocated = 0;
4530 }
4531 set_dor(0, ~0, 8);
4532#if N_FDC > 1
4533 set_dor(1, ~8, 0);
4534#endif
4535 floppy_enable_hlt();
4536
4537 if (floppy_track_buffer && max_buffer_sectors) {
4538 tmpsize = max_buffer_sectors * 1024;
4539 tmpaddr = (unsigned long)floppy_track_buffer;
4540 floppy_track_buffer = NULL;
4541 max_buffer_sectors = 0;
4542 buffer_min = buffer_max = -1;
4543 fd_dma_mem_free(tmpaddr, tmpsize);
4544 }
4545#ifdef FLOPPY_SANITY_CHECK
4546#ifndef __sparc__
4547 for (drive = 0; drive < N_FDC * 4; drive++)
4548 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004549 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550#endif
4551
4552 if (timer_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004553 pr_info("floppy timer still active:%s\n", timeout_message);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004555 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004556 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004557 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558#endif
4559 old_fdc = fdc;
4560 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004561 if (FDCS->address != -1)
4562 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 fdc = old_fdc;
4564}
4565
4566#ifdef MODULE
4567
4568static char *floppy;
4569
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570static void __init parse_floppy_cfg_string(char *cfg)
4571{
4572 char *ptr;
4573
4574 while (*cfg) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004575 ptr = cfg;
4576 while (*cfg && *cfg != ' ' && *cfg != '\t')
4577 cfg++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 if (*cfg) {
4579 *cfg = '\0';
4580 cfg++;
4581 }
4582 if (*ptr)
4583 floppy_setup(ptr);
4584 }
4585}
4586
Jon Schindler7afea3b2008-04-29 00:59:21 -07004587static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588{
4589 if (floppy)
4590 parse_floppy_cfg_string(floppy);
4591 return floppy_init();
4592}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004593module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594
Jon Schindler7afea3b2008-04-29 00:59:21 -07004595static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596{
4597 int drive;
4598
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4600 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004601 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004602
4603 for (drive = 0; drive < N_DRIVE; drive++) {
4604 del_timer_sync(&motor_off_timer[drive]);
4605
4606 if ((allowed_drive_mask & (1 << drive)) &&
4607 fdc_state[FDC(drive)].version != FDC_NONE) {
4608 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004609 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4610 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 }
4612 put_disk(disks[drive]);
4613 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614
4615 del_timer_sync(&fd_timeout);
4616 del_timer_sync(&fd_timer);
4617 blk_cleanup_queue(floppy_queue);
4618
4619 if (usage_count)
4620 floppy_release_irq_and_dma();
4621
4622 /* eject disk, if any */
4623 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624}
Joe Perches48c8cee2010-03-10 15:20:45 -08004625
Jon Schindler7afea3b2008-04-29 00:59:21 -07004626module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627
4628module_param(floppy, charp, 0);
4629module_param(FLOPPY_IRQ, int, 0);
4630module_param(FLOPPY_DMA, int, 0);
4631MODULE_AUTHOR("Alain L. Knaff");
4632MODULE_SUPPORTED_DEVICE("fd");
4633MODULE_LICENSE("GPL");
4634
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004635/* This doesn't actually get used other than for module information */
4636static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004637 {"PNP0700", 0},
4638 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004639};
Joe Perches48c8cee2010-03-10 15:20:45 -08004640
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004641MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4642
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643#else
4644
4645__setup("floppy=", floppy_setup);
4646module_init(floppy_init)
4647#endif
4648
4649MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);