blob: 50bd9e9370ddad6a6f404246a09c8425dd0416b6 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/block/floppy.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 * Copyright (C) 1993, 1994 Alain Knaff
6 * Copyright (C) 1998 Alan Cox
7 */
Jesper Juhl06f748c2007-10-16 23:30:57 -07008
Linus Torvalds1da177e2005-04-16 15:20:36 -07009/*
10 * 02.12.91 - Changed to static variables to indicate need for reset
11 * and recalibrate. This makes some things easier (output_byte reset
12 * checking etc), and means less interrupt jumping in case of errors,
13 * so the code is hopefully easier to understand.
14 */
15
16/*
17 * This file is certainly a mess. I've tried my best to get it working,
18 * but I don't like programming floppies, and I have only one anyway.
19 * Urgel. I should check for more errors, and do more graceful error
20 * recovery. Seems there are problems with several drives. I've tried to
21 * correct them. No promises.
22 */
23
24/*
25 * As with hd.c, all routines within this file can (and will) be called
26 * by interrupts, so extreme caution is needed. A hardware interrupt
27 * handler may not sleep, or a kernel panic will happen. Thus I cannot
28 * call "floppy-on" directly, but have to set a special timer interrupt
29 * etc.
30 */
31
32/*
33 * 28.02.92 - made track-buffering routines, based on the routines written
34 * by entropy@wintermute.wpi.edu (Lawrence Foard). Linus.
35 */
36
37/*
38 * Automatic floppy-detection and formatting written by Werner Almesberger
39 * (almesber@nessie.cs.id.ethz.ch), who also corrected some problems with
40 * the floppy-change signal detection.
41 */
42
43/*
44 * 1992/7/22 -- Hennus Bergman: Added better error reporting, fixed
45 * FDC data overrun bug, added some preliminary stuff for vertical
46 * recording support.
47 *
48 * 1992/9/17: Added DMA allocation & DMA functions. -- hhb.
49 *
50 * TODO: Errors are still not counted properly.
51 */
52
53/* 1992/9/20
54 * Modifications for ``Sector Shifting'' by Rob Hooft (hooft@chem.ruu.nl)
55 * modeled after the freeware MS-DOS program fdformat/88 V1.8 by
56 * Christoph H. Hochst\"atter.
57 * I have fixed the shift values to the ones I always use. Maybe a new
58 * ioctl() should be created to be able to modify them.
59 * There is a bug in the driver that makes it impossible to format a
60 * floppy as the first thing after bootup.
61 */
62
63/*
64 * 1993/4/29 -- Linus -- cleaned up the timer handling in the kernel, and
65 * this helped the floppy driver as well. Much cleaner, and still seems to
66 * work.
67 */
68
69/* 1994/6/24 --bbroad-- added the floppy table entries and made
70 * minor modifications to allow 2.88 floppies to be run.
71 */
72
73/* 1994/7/13 -- Paul Vojta -- modified the probing code to allow three or more
74 * disk types.
75 */
76
77/*
78 * 1994/8/8 -- Alain Knaff -- Switched to fdpatch driver: Support for bigger
79 * format bug fixes, but unfortunately some new bugs too...
80 */
81
82/* 1994/9/17 -- Koen Holtman -- added logging of physical floppy write
83 * errors to allow safe writing by specialized programs.
84 */
85
86/* 1995/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks
87 * by defining bit 1 of the "stretch" parameter to mean put sectors on the
88 * opposite side of the disk, leaving the sector IDs alone (i.e. Commodore's
89 * drives are "upside-down").
90 */
91
92/*
93 * 1995/8/26 -- Andreas Busse -- added Mips support.
94 */
95
96/*
97 * 1995/10/18 -- Ralf Baechle -- Portability cleanup; move machine dependent
98 * features to asm/floppy.h.
99 */
100
101/*
James Nelsonb88b0982005-11-08 16:52:12 +0100102 * 1998/1/21 -- Richard Gooch <rgooch@atnf.csiro.au> -- devfs support
103 */
104
105/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 * 1998/05/07 -- Russell King -- More portability cleanups; moved definition of
107 * interrupt and dma channel to asm/floppy.h. Cleaned up some formatting &
108 * use of '0' for NULL.
109 */
110
111/*
112 * 1998/06/07 -- Alan Cox -- Merged the 2.0.34 fixes for resource allocation
113 * failures.
114 */
115
116/*
117 * 1998/09/20 -- David Weinehall -- Added slow-down code for buggy PS/2-drives.
118 */
119
120/*
121 * 1999/08/13 -- Paul Slootman -- floppy stopped working on Alpha after 24
122 * days, 6 hours, 32 minutes and 32 seconds (i.e. MAXINT jiffies; ints were
123 * being used to store jiffies, which are unsigned longs).
124 */
125
126/*
127 * 2000/08/28 -- Arnaldo Carvalho de Melo <acme@conectiva.com.br>
128 * - get rid of check_region
129 * - s/suser/capable/
130 */
131
132/*
133 * 2001/08/26 -- Paul Gortmaker - fix insmod oops on machines with no
134 * floppy controller (lingering task on list after module is gone... boom.)
135 */
136
137/*
138 * 2002/02/07 -- Anton Altaparmakov - Fix io ports reservation to correct range
139 * (0x3f2-0x3f5, 0x3f7). This fix is a bit of a hack but the proper fix
140 * requires many non-obvious changes in arch dependent code.
141 */
142
143/* 2003/07/28 -- Daniele Bellucci <bellucda@tiscali.it>.
144 * Better audit of register_blkdev.
145 */
146
147#define FLOPPY_SANITY_CHECK
148#undef FLOPPY_SILENT_DCL_CLEAR
149
150#define REALLY_SLOW_IO
151
152#define DEBUGT 2
Joe Perches48c8cee2010-03-10 15:20:45 -0800153#define DCL_DEBUG /* debug disk change line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
155/* do print messages for unexpected interrupts */
156static int print_unex = 1;
157#include <linux/module.h>
158#include <linux/sched.h>
159#include <linux/fs.h>
160#include <linux/kernel.h>
161#include <linux/timer.h>
162#include <linux/workqueue.h>
163#define FDPATCHES
164#include <linux/fdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165#include <linux/fd.h>
166#include <linux/hdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167#include <linux/errno.h>
168#include <linux/slab.h>
169#include <linux/mm.h>
170#include <linux/bio.h>
171#include <linux/string.h>
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800172#include <linux/jiffies.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173#include <linux/fcntl.h>
174#include <linux/delay.h>
175#include <linux/mc146818rtc.h> /* CMOS defines */
176#include <linux/ioport.h>
177#include <linux/interrupt.h>
178#include <linux/init.h>
Russell Kingd052d1b2005-10-29 19:07:23 +0100179#include <linux/platform_device.h>
Scott James Remnant83f9ef42009-04-02 16:56:47 -0700180#include <linux/mod_devicetable.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181#include <linux/buffer_head.h> /* for invalidate_buffers() */
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800182#include <linux/mutex.h>
Joe Perchesd4937542010-03-10 15:20:44 -0800183#include <linux/io.h>
184#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185
186/*
187 * PS/2 floppies have much slower step rates than regular floppies.
188 * It's been recommended that take about 1/4 of the default speed
189 * in some more extreme cases.
190 */
191static int slow_floppy;
192
193#include <asm/dma.h>
194#include <asm/irq.h>
195#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
197static int FLOPPY_IRQ = 6;
198static int FLOPPY_DMA = 2;
199static int can_use_virtual_dma = 2;
200/* =======
201 * can use virtual DMA:
202 * 0 = use of virtual DMA disallowed by config
203 * 1 = use of virtual DMA prescribed by config
204 * 2 = no virtual DMA preference configured. By default try hard DMA,
205 * but fall back on virtual DMA when not enough memory available
206 */
207
208static int use_virtual_dma;
209/* =======
210 * use virtual DMA
211 * 0 using hard DMA
212 * 1 using virtual DMA
213 * This variable is set to virtual when a DMA mem problem arises, and
214 * reset back in floppy_grab_irq_and_dma.
215 * It is not safe to reset it in other circumstances, because the floppy
216 * driver may have several buffers in use at once, and we do currently not
217 * record each buffers capabilities
218 */
219
220static DEFINE_SPINLOCK(floppy_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221
222static unsigned short virtual_dma_port = 0x3f0;
David Howells7d12e782006-10-05 14:55:46 +0100223irqreturn_t floppy_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224static int set_dor(int fdc, char mask, char data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
226#define K_64 0x10000 /* 64KB */
227
228/* the following is the mask of allowed drives. By default units 2 and
229 * 3 of both floppy controllers are disabled, because switching on the
230 * motor of these drives causes system hangs on some PCI computers. drive
231 * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
232 * a drive is allowed.
233 *
234 * NOTE: This must come before we include the arch floppy header because
235 * some ports reference this variable from there. -DaveM
236 */
237
238static int allowed_drive_mask = 0x33;
239
240#include <asm/floppy.h>
241
242static int irqdma_allocated;
243
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244#define DEVICE_NAME "floppy"
245
246#include <linux/blkdev.h>
247#include <linux/blkpg.h>
248#include <linux/cdrom.h> /* for the compatibility eject ioctl */
249#include <linux/completion.h>
250
251static struct request *current_req;
252static struct request_queue *floppy_queue;
Joe Perches48c8cee2010-03-10 15:20:45 -0800253static void do_fd_request(struct request_queue *q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
255#ifndef fd_get_dma_residue
256#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
257#endif
258
259/* Dma Memory related stuff */
260
261#ifndef fd_dma_mem_free
262#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
263#endif
264
265#ifndef fd_dma_mem_alloc
Joe Perches48c8cee2010-03-10 15:20:45 -0800266#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL, get_order(size))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267#endif
268
269static inline void fallback_on_nodma_alloc(char **addr, size_t l)
270{
271#ifdef FLOPPY_CAN_FALLBACK_ON_NODMA
272 if (*addr)
273 return; /* we have the memory */
274 if (can_use_virtual_dma != 2)
275 return; /* no fallback allowed */
Joe Perchesb46df352010-03-10 15:20:46 -0800276 pr_info("DMA memory shortage. Temporarily falling back on virtual DMA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 *addr = (char *)nodma_mem_alloc(l);
278#else
279 return;
280#endif
281}
282
283/* End dma memory related stuff */
284
285static unsigned long fake_change;
286static int initialising = 1;
287
Joe Perches48c8cee2010-03-10 15:20:45 -0800288#define ITYPE(x) (((x) >> 2) & 0x1f)
289#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
290#define UNIT(x) ((x) & 0x03) /* drive on fdc */
291#define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700292 /* reverse mapping from unit and fdc to drive */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
Joe Perches48c8cee2010-03-10 15:20:45 -0800295#define DP (&drive_params[current_drive])
296#define DRS (&drive_state[current_drive])
297#define DRWE (&write_errors[current_drive])
298#define FDCS (&fdc_state[fdc])
299#define CLEARF(x) clear_bit(x##_BIT, &DRS->flags)
300#define SETF(x) set_bit(x##_BIT, &DRS->flags)
301#define TESTF(x) test_bit(x##_BIT, &DRS->flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
Joe Perches48c8cee2010-03-10 15:20:45 -0800303#define UDP (&drive_params[drive])
304#define UDRS (&drive_state[drive])
305#define UDRWE (&write_errors[drive])
306#define UFDCS (&fdc_state[FDC(drive)])
307#define UCLEARF(x) clear_bit(x##_BIT, &UDRS->flags)
308#define USETF(x) set_bit(x##_BIT, &UDRS->flags)
309#define UTESTF(x) test_bit(x##_BIT, &UDRS->flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Joe Perches48c8cee2010-03-10 15:20:45 -0800311#define DPRINT(format, args...) \
Joe Perchesb46df352010-03-10 15:20:46 -0800312 pr_info(DEVICE_NAME "%d: " format, current_drive, ##args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
Joe Perches48c8cee2010-03-10 15:20:45 -0800314#define PH_HEAD(floppy, head) (((((floppy)->stretch & 2) >> 1) ^ head) << 2)
315#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
316
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317/* read/write */
Joe Perches48c8cee2010-03-10 15:20:45 -0800318#define COMMAND (raw_cmd->cmd[0])
319#define DR_SELECT (raw_cmd->cmd[1])
320#define TRACK (raw_cmd->cmd[2])
321#define HEAD (raw_cmd->cmd[3])
322#define SECTOR (raw_cmd->cmd[4])
323#define SIZECODE (raw_cmd->cmd[5])
324#define SECT_PER_TRACK (raw_cmd->cmd[6])
325#define GAP (raw_cmd->cmd[7])
326#define SIZECODE2 (raw_cmd->cmd[8])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327#define NR_RW 9
328
329/* format */
Joe Perches48c8cee2010-03-10 15:20:45 -0800330#define F_SIZECODE (raw_cmd->cmd[2])
331#define F_SECT_PER_TRACK (raw_cmd->cmd[3])
332#define F_GAP (raw_cmd->cmd[4])
333#define F_FILL (raw_cmd->cmd[5])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334#define NR_F 6
335
336/*
Joe Perches48c8cee2010-03-10 15:20:45 -0800337 * Maximum disk size (in kilobytes).
338 * This default is used whenever the current disk size is unknown.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 * [Now it is rather a minimum]
340 */
341#define MAX_DISK_SIZE 4 /* 3984 */
342
343/*
344 * globals used by 'result()'
345 */
346#define MAX_REPLIES 16
347static unsigned char reply_buffer[MAX_REPLIES];
348static int inr; /* size of reply buffer, when called from interrupt */
Joe Perches48c8cee2010-03-10 15:20:45 -0800349#define ST0 (reply_buffer[0])
350#define ST1 (reply_buffer[1])
351#define ST2 (reply_buffer[2])
352#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
353#define R_TRACK (reply_buffer[3])
354#define R_HEAD (reply_buffer[4])
355#define R_SECTOR (reply_buffer[5])
356#define R_SIZECODE (reply_buffer[6])
357
358#define SEL_DLY (2 * HZ / 100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
360/*
361 * this struct defines the different floppy drive types.
362 */
363static struct {
364 struct floppy_drive_params params;
365 const char *name; /* name printed while booting */
366} default_drive_params[] = {
367/* NOTE: the time values in jiffies should be in msec!
368 CMOS drive type
369 | Maximum data rate supported by drive type
370 | | Head load time, msec
371 | | | Head unload time, msec (not used)
372 | | | | Step rate interval, usec
373 | | | | | Time needed for spinup time (jiffies)
374 | | | | | | Timeout for spinning down (jiffies)
375 | | | | | | | Spindown offset (where disk stops)
376 | | | | | | | | Select delay
377 | | | | | | | | | RPS
378 | | | | | | | | | | Max number of tracks
379 | | | | | | | | | | | Interrupt timeout
380 | | | | | | | | | | | | Max nonintlv. sectors
381 | | | | | | | | | | | | | -Max Errors- flags */
382{{0, 500, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 80, 3*HZ, 20, {3,1,2,0,2}, 0,
383 0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },
384
385{{1, 300, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 40, 3*HZ, 17, {3,1,2,0,2}, 0,
386 0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
387
388{{2, 500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0,
389 0, { 2, 5, 6,23,10,20,12, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/
390
391{{3, 250, 16, 16, 3000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
392 0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/
393
394{{4, 500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
395 0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/
396
397{{5, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
398 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
399
400{{6, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
401 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*/
402/* | --autodetected formats--- | | |
403 * read_track | | Name printed when booting
404 * | Native format
405 * Frequency of disk change checks */
406};
407
408static struct floppy_drive_params drive_params[N_DRIVE];
409static struct floppy_drive_struct drive_state[N_DRIVE];
410static struct floppy_write_errors write_errors[N_DRIVE];
411static struct timer_list motor_off_timer[N_DRIVE];
412static struct gendisk *disks[N_DRIVE];
413static struct block_device *opened_bdev[N_DRIVE];
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800414static DEFINE_MUTEX(open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
416
417/*
418 * This struct defines the different floppy types.
419 *
420 * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
421 * types (e.g. 360kB diskette in 1.2MB drive, etc.). Bit 1 of 'stretch'
422 * tells if the disk is in Commodore 1581 format, which means side 0 sectors
423 * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
424 * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
425 * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
426 * side 0 is on physical side 0 (but with the misnamed sector IDs).
427 * 'stretch' should probably be renamed to something more general, like
Keith Wansbrough9e491842008-09-22 14:57:17 -0700428 * 'options'.
429 *
430 * Bits 2 through 9 of 'stretch' tell the number of the first sector.
431 * The LSB (bit 2) is flipped. For most disks, the first sector
432 * is 1 (represented by 0x00<<2). For some CP/M and music sampler
433 * disks (such as Ensoniq EPS 16plus) it is 0 (represented as 0x01<<2).
434 * For Amstrad CPC disks it is 0xC1 (represented as 0xC0<<2).
435 *
436 * Other parameters should be self-explanatory (see also setfdprm(8)).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 */
438/*
439 Size
440 | Sectors per track
441 | | Head
442 | | | Tracks
443 | | | | Stretch
444 | | | | | Gap 1 size
445 | | | | | | Data rate, | 0x40 for perp
446 | | | | | | | Spec1 (stepping rate, head unload
447 | | | | | | | | /fmt gap (gap2) */
448static struct floppy_struct floppy_type[32] = {
449 { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* 0 no testing */
450 { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360" }, /* 1 360KB PC */
451 { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" }, /* 2 1.2MB AT */
452 { 720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360" }, /* 3 360KB SS 3.5" */
453 { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720" }, /* 4 720KB 3.5" */
454 { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360" }, /* 5 360KB AT */
455 { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" }, /* 6 720KB AT */
456 { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /* 7 1.44MB 3.5" */
457 { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /* 8 2.88MB 3.5" */
458 { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" }, /* 9 3.12MB 3.5" */
459
460 { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */
461 { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */
462 { 820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410" }, /* 12 410KB 5.25" */
463 { 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820" }, /* 13 820KB 3.5" */
464 { 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" }, /* 14 1.48MB 5.25" */
465 { 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" }, /* 15 1.72MB 3.5" */
466 { 840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420" }, /* 16 420KB 5.25" */
467 { 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830" }, /* 17 830KB 3.5" */
468 { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" }, /* 18 1.49MB 5.25" */
469 { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5" */
470
471 { 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880" }, /* 20 880KB 5.25" */
472 { 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5" */
473 { 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5" */
474 { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25" */
475 { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5" */
476 { 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5" */
477 { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5" */
478 { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5" */
479 { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5" */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5" */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700481
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */
483 { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */
484};
485
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486#define SECTSIZE (_FD_SECTSIZE(*floppy))
487
488/* Auto-detection: Disk type used until the next media change occurs. */
489static struct floppy_struct *current_type[N_DRIVE];
490
491/*
492 * User-provided type information. current_type points to
493 * the respective entry of this array.
494 */
495static struct floppy_struct user_params[N_DRIVE];
496
497static sector_t floppy_sizes[256];
498
Hannes Reinecke94fd0db2005-07-15 10:09:25 +0200499static char floppy_device_name[] = "floppy";
500
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501/*
502 * The driver is trying to determine the correct media format
503 * while probing is set. rw_interrupt() clears it after a
504 * successful access.
505 */
506static int probing;
507
508/* Synchronization of FDC access. */
Joe Perches48c8cee2010-03-10 15:20:45 -0800509#define FD_COMMAND_NONE -1
510#define FD_COMMAND_ERROR 2
511#define FD_COMMAND_OKAY 3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
513static volatile int command_status = FD_COMMAND_NONE;
514static unsigned long fdc_busy;
515static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
516static DECLARE_WAIT_QUEUE_HEAD(command_done);
517
518#define NO_SIGNAL (!interruptible || !signal_pending(current))
Joe Perches48c8cee2010-03-10 15:20:45 -0800519#define CALL(x) if ((x) == -EINTR) return -EINTR
520#define ECALL(x) if ((ret = (x))) return ret;
521#define _WAIT(x,i) CALL(ret=wait_til_done((x),i))
522#define WAIT(x) _WAIT((x),interruptible)
523#define IWAIT(x) _WAIT((x),1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
525/* Errors during formatting are counted here. */
526static int format_errors;
527
528/* Format request descriptor. */
529static struct format_descr format_req;
530
531/*
532 * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
533 * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
534 * H is head unload time (1=16ms, 2=32ms, etc)
535 */
536
537/*
538 * Track buffer
539 * Because these are written to by the DMA controller, they must
540 * not contain a 64k byte boundary crossing, or data will be
541 * corrupted/lost.
542 */
543static char *floppy_track_buffer;
544static int max_buffer_sectors;
545
546static int *errors;
Jesper Juhl06f748c2007-10-16 23:30:57 -0700547typedef void (*done_f)(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548static struct cont_t {
Joe Perches48c8cee2010-03-10 15:20:45 -0800549 void (*interrupt)(void);
550 /* this is called after the interrupt of the
551 * main command */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700552 void (*redo)(void); /* this is called to retry the operation */
553 void (*error)(void); /* this is called to tally an error */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 done_f done; /* this is called to say if the operation has
555 * succeeded/failed */
556} *cont;
557
558static void floppy_ready(void);
559static void floppy_start(void);
560static void process_fd_request(void);
561static void recalibrate_floppy(void);
562static void floppy_shutdown(unsigned long);
563
Philippe De Muyter5a74db02009-02-18 14:48:36 -0800564static int floppy_request_regions(int);
565static void floppy_release_regions(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566static int floppy_grab_irq_and_dma(void);
567static void floppy_release_irq_and_dma(void);
568
569/*
570 * The "reset" variable should be tested whenever an interrupt is scheduled,
571 * after the commands have been sent. This is to ensure that the driver doesn't
572 * get wedged when the interrupt doesn't come because of a failed command.
573 * reset doesn't need to be tested before sending commands, because
574 * output_byte is automatically disabled when reset is set.
575 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576static void reset_fdc(void);
577
578/*
579 * These are global variables, as that's the easiest way to give
580 * information to interrupts. They are the data used for the current
581 * request.
582 */
Joe Perches48c8cee2010-03-10 15:20:45 -0800583#define NO_TRACK -1
584#define NEED_1_RECAL -2
585#define NEED_2_RECAL -3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
587static int usage_count;
588
589/* buffer related variables */
590static int buffer_track = -1;
591static int buffer_drive = -1;
592static int buffer_min = -1;
593static int buffer_max = -1;
594
595/* fdc related variables, should end up in a struct */
596static struct floppy_fdc_state fdc_state[N_FDC];
597static int fdc; /* current fdc */
598
599static struct floppy_struct *_floppy = floppy_type;
600static unsigned char current_drive;
601static long current_count_sectors;
602static unsigned char fsector_t; /* sector in track */
603static unsigned char in_sector_offset; /* offset within physical sector,
604 * expressed in units of 512 bytes */
605
606#ifndef fd_eject
607static inline int fd_eject(int drive)
608{
609 return -EINVAL;
610}
611#endif
612
613/*
614 * Debugging
615 * =========
616 */
617#ifdef DEBUGT
618static long unsigned debugtimer;
619
620static inline void set_debugt(void)
621{
622 debugtimer = jiffies;
623}
624
625static inline void debugt(const char *message)
626{
627 if (DP->flags & DEBUGT)
Joe Perchesb46df352010-03-10 15:20:46 -0800628 pr_info("%s dtime=%lu\n", message, jiffies - debugtimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629}
630#else
631static inline void set_debugt(void) { }
632static inline void debugt(const char *message) { }
633#endif /* DEBUGT */
634
Joe Perchesa0a52d62010-03-10 15:20:52 -0800635typedef void (*timeout_fn)(unsigned long);
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700636static DEFINE_TIMER(fd_timeout, floppy_shutdown, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
638static const char *timeout_message;
639
640#ifdef FLOPPY_SANITY_CHECK
641static void is_alive(const char *message)
642{
643 /* this routine checks whether the floppy driver is "alive" */
644 if (test_bit(0, &fdc_busy) && command_status < 2
645 && !timer_pending(&fd_timeout)) {
646 DPRINT("timeout handler died: %s\n", message);
647 }
648}
649#endif
650
Joe Perches48c8cee2010-03-10 15:20:45 -0800651static void (*do_floppy)(void) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
653#ifdef FLOPPY_SANITY_CHECK
654
655#define OLOGSIZE 20
656
Joe Perches48c8cee2010-03-10 15:20:45 -0800657static void (*lasthandler)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658static unsigned long interruptjiffies;
659static unsigned long resultjiffies;
660static int resultsize;
661static unsigned long lastredo;
662
663static struct output_log {
664 unsigned char data;
665 unsigned char status;
666 unsigned long jiffies;
667} output_log[OLOGSIZE];
668
669static int output_log_pos;
670#endif
671
672#define current_reqD -1
673#define MAXTIMEOUT -2
674
675static void __reschedule_timeout(int drive, const char *message, int marg)
676{
677 if (drive == current_reqD)
678 drive = current_drive;
679 del_timer(&fd_timeout);
Eric Sesterhenn / Snakebyte4acb3e22007-05-23 13:58:15 -0700680 if (drive < 0 || drive >= N_DRIVE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 fd_timeout.expires = jiffies + 20UL * HZ;
682 drive = 0;
683 } else
684 fd_timeout.expires = jiffies + UDP->timeout;
685 add_timer(&fd_timeout);
Joe Perchesa81ee542010-03-10 15:20:46 -0800686 if (UDP->flags & FD_DEBUG)
Joe Perchesb46df352010-03-10 15:20:46 -0800687 DPRINT("reschedule timeout %s %d\n", message, marg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 timeout_message = message;
689}
690
691static void reschedule_timeout(int drive, const char *message, int marg)
692{
693 unsigned long flags;
694
695 spin_lock_irqsave(&floppy_lock, flags);
696 __reschedule_timeout(drive, message, marg);
697 spin_unlock_irqrestore(&floppy_lock, flags);
698}
699
Joe Perches48c8cee2010-03-10 15:20:45 -0800700#define INFBOUND(a, b) (a) = max_t(int, a, b)
701#define SUPBOUND(a, b) (a) = min_t(int, a, b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
703/*
704 * Bottom half floppy driver.
705 * ==========================
706 *
707 * This part of the file contains the code talking directly to the hardware,
708 * and also the main service loop (seek-configure-spinup-command)
709 */
710
711/*
712 * disk change.
713 * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
714 * and the last_checked date.
715 *
716 * last_checked is the date of the last check which showed 'no disk change'
717 * FD_DISK_CHANGE is set under two conditions:
718 * 1. The floppy has been changed after some i/o to that floppy already
719 * took place.
720 * 2. No floppy disk is in the drive. This is done in order to ensure that
721 * requests are quickly flushed in case there is no disk in the drive. It
722 * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
723 * the drive.
724 *
725 * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
726 * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
727 * each seek. If a disk is present, the disk change line should also be
728 * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
729 * change line is set, this means either that no disk is in the drive, or
730 * that it has been removed since the last seek.
731 *
732 * This means that we really have a third possibility too:
733 * The floppy has been changed after the last seek.
734 */
735
736static int disk_change(int drive)
737{
738 int fdc = FDC(drive);
Jesper Juhl06f748c2007-10-16 23:30:57 -0700739
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740#ifdef FLOPPY_SANITY_CHECK
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800741 if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 DPRINT("WARNING disk change called early\n");
743 if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
744 (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
745 DPRINT("probing disk change on unselected drive\n");
746 DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
747 (unsigned int)FDCS->dor);
748 }
749#endif
750
751#ifdef DCL_DEBUG
752 if (UDP->flags & FD_DEBUG) {
753 DPRINT("checking disk change line for drive %d\n", drive);
754 DPRINT("jiffies=%lu\n", jiffies);
755 DPRINT("disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
756 DPRINT("flags=%lx\n", UDRS->flags);
757 }
758#endif
759 if (UDP->flags & FD_BROKEN_DCL)
760 return UTESTF(FD_DISK_CHANGED);
761 if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
762 USETF(FD_VERIFY); /* verify write protection */
763 if (UDRS->maxblock) {
764 /* mark it changed */
765 USETF(FD_DISK_CHANGED);
766 }
767
768 /* invalidate its geometry */
769 if (UDRS->keep_data >= 0) {
770 if ((UDP->flags & FTD_MSG) &&
771 current_type[drive] != NULL)
772 DPRINT("Disk type is undefined after "
773 "disk change\n");
774 current_type[drive] = NULL;
775 floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
776 }
777
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 return 1;
779 } else {
780 UDRS->last_checked = jiffies;
781 UCLEARF(FD_DISK_NEWCHANGE);
782 }
783 return 0;
784}
785
786static inline int is_selected(int dor, int unit)
787{
788 return ((dor & (0x10 << unit)) && (dor & 3) == unit);
789}
790
791static int set_dor(int fdc, char mask, char data)
792{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700793 unsigned char unit;
794 unsigned char drive;
795 unsigned char newdor;
796 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
798 if (FDCS->address == -1)
799 return -1;
800
801 olddor = FDCS->dor;
802 newdor = (olddor & mask) | data;
803 if (newdor != olddor) {
804 unit = olddor & 0x3;
805 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
806 drive = REVDRIVE(fdc, unit);
807#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -0800808 if (UDP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 DPRINT("calling disk change from set_dor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810#endif
811 disk_change(drive);
812 }
813 FDCS->dor = newdor;
814 fd_outb(newdor, FD_DOR);
815
816 unit = newdor & 0x3;
817 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
818 drive = REVDRIVE(fdc, unit);
819 UDRS->select_date = jiffies;
820 }
821 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 return olddor;
823}
824
825static void twaddle(void)
826{
827 if (DP->select_delay)
828 return;
829 fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
830 fd_outb(FDCS->dor, FD_DOR);
831 DRS->select_date = jiffies;
832}
833
834/* reset all driver information about the current fdc. This is needed after
835 * a reset, and after a raw command. */
836static void reset_fdc_info(int mode)
837{
838 int drive;
839
840 FDCS->spec1 = FDCS->spec2 = -1;
841 FDCS->need_configure = 1;
842 FDCS->perp_mode = 1;
843 FDCS->rawcmd = 0;
844 for (drive = 0; drive < N_DRIVE; drive++)
845 if (FDC(drive) == fdc && (mode || UDRS->track != NEED_1_RECAL))
846 UDRS->track = NEED_2_RECAL;
847}
848
849/* selects the fdc and drive, and enables the fdc's input/dma. */
850static void set_fdc(int drive)
851{
852 if (drive >= 0 && drive < N_DRIVE) {
853 fdc = FDC(drive);
854 current_drive = drive;
855 }
856 if (fdc != 1 && fdc != 0) {
Joe Perchesb46df352010-03-10 15:20:46 -0800857 pr_info("bad fdc value\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 return;
859 }
860 set_dor(fdc, ~0, 8);
861#if N_FDC > 1
862 set_dor(1 - fdc, ~8, 0);
863#endif
864 if (FDCS->rawcmd == 2)
865 reset_fdc_info(1);
866 if (fd_inb(FD_STATUS) != STATUS_READY)
867 FDCS->reset = 1;
868}
869
870/* locks the driver */
871static int _lock_fdc(int drive, int interruptible, int line)
872{
873 if (!usage_count) {
Joe Perchesb46df352010-03-10 15:20:46 -0800874 pr_err("Trying to lock fdc while usage count=0 at line %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 line);
876 return -1;
877 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
879 if (test_and_set_bit(0, &fdc_busy)) {
880 DECLARE_WAITQUEUE(wait, current);
881 add_wait_queue(&fdc_wait, &wait);
882
883 for (;;) {
884 set_current_state(TASK_INTERRUPTIBLE);
885
886 if (!test_and_set_bit(0, &fdc_busy))
887 break;
888
889 schedule();
890
891 if (!NO_SIGNAL) {
892 remove_wait_queue(&fdc_wait, &wait);
893 return -EINTR;
894 }
895 }
896
897 set_current_state(TASK_RUNNING);
898 remove_wait_queue(&fdc_wait, &wait);
Ingo Molnar3e541a42006-07-03 00:24:23 -0700899 flush_scheduled_work();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 }
901 command_status = FD_COMMAND_NONE;
902
903 __reschedule_timeout(drive, "lock fdc", 0);
904 set_fdc(drive);
905 return 0;
906}
907
Joe Perches48c8cee2010-03-10 15:20:45 -0800908#define lock_fdc(drive, interruptible) \
909 _lock_fdc(drive, interruptible, __LINE__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911/* unlocks the driver */
912static inline void unlock_fdc(void)
913{
914 unsigned long flags;
915
916 raw_cmd = NULL;
917 if (!test_bit(0, &fdc_busy))
918 DPRINT("FDC access conflict!\n");
919
920 if (do_floppy)
921 DPRINT("device interrupt still active at FDC release: %p!\n",
922 do_floppy);
923 command_status = FD_COMMAND_NONE;
924 spin_lock_irqsave(&floppy_lock, flags);
925 del_timer(&fd_timeout);
926 cont = NULL;
927 clear_bit(0, &fdc_busy);
Tejun Heo9934c8c2009-05-08 11:54:16 +0900928 if (current_req || blk_peek_request(floppy_queue))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 do_fd_request(floppy_queue);
930 spin_unlock_irqrestore(&floppy_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 wake_up(&fdc_wait);
932}
933
934/* switches the motor off after a given timeout */
935static void motor_off_callback(unsigned long nr)
936{
937 unsigned char mask = ~(0x10 << UNIT(nr));
938
939 set_dor(FDC(nr), mask, 0);
940}
941
942/* schedules motor off */
943static void floppy_off(unsigned int drive)
944{
945 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700946 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
948 if (!(FDCS->dor & (0x10 << UNIT(drive))))
949 return;
950
951 del_timer(motor_off_timer + drive);
952
953 /* make spindle stop in a position which minimizes spinup time
954 * next time */
955 if (UDP->rps) {
956 delta = jiffies - UDRS->first_read_date + HZ -
957 UDP->spindown_offset;
958 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
959 motor_off_timer[drive].expires =
960 jiffies + UDP->spindown - delta;
961 }
962 add_timer(motor_off_timer + drive);
963}
964
965/*
966 * cycle through all N_DRIVE floppy drives, for disk change testing.
967 * stopping at current drive. This is done before any long operation, to
968 * be sure to have up to date disk change information.
969 */
970static void scandrives(void)
971{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700972 int i;
973 int drive;
974 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
976 if (DP->select_delay)
977 return;
978
979 saved_drive = current_drive;
980 for (i = 0; i < N_DRIVE; i++) {
981 drive = (saved_drive + i + 1) % N_DRIVE;
982 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
983 continue; /* skip closed drives */
984 set_fdc(drive);
985 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
986 (0x10 << UNIT(drive))))
987 /* switch the motor off again, if it was off to
988 * begin with */
989 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
990 }
991 set_fdc(saved_drive);
992}
993
994static void empty(void)
995{
996}
997
David Howells65f27f32006-11-22 14:55:48 +0000998static DECLARE_WORK(floppy_work, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
Joe Perches48c8cee2010-03-10 15:20:45 -08001000static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001{
David Howells65f27f32006-11-22 14:55:48 +00001002 PREPARE_WORK(&floppy_work, (work_func_t)handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 schedule_work(&floppy_work);
1004}
1005
Ingo Molnar8d06afa2005-09-09 13:10:40 -07001006static DEFINE_TIMER(fd_timer, NULL, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007
1008static void cancel_activity(void)
1009{
1010 unsigned long flags;
1011
1012 spin_lock_irqsave(&floppy_lock, flags);
1013 do_floppy = NULL;
David Howells65f27f32006-11-22 14:55:48 +00001014 PREPARE_WORK(&floppy_work, (work_func_t)empty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 del_timer(&fd_timer);
1016 spin_unlock_irqrestore(&floppy_lock, flags);
1017}
1018
1019/* this function makes sure that the disk stays in the drive during the
1020 * transfer */
1021static void fd_watchdog(void)
1022{
1023#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08001024 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 DPRINT("calling disk change from watchdog\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026#endif
1027
1028 if (disk_change(current_drive)) {
1029 DPRINT("disk removed during i/o\n");
1030 cancel_activity();
1031 cont->done(0);
1032 reset_fdc();
1033 } else {
1034 del_timer(&fd_timer);
Joe Perchesa0a52d62010-03-10 15:20:52 -08001035 fd_timer.function = (timeout_fn)fd_watchdog;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 fd_timer.expires = jiffies + HZ / 10;
1037 add_timer(&fd_timer);
1038 }
1039}
1040
1041static void main_command_interrupt(void)
1042{
1043 del_timer(&fd_timer);
1044 cont->interrupt();
1045}
1046
1047/* waits for a delay (spinup or select) to pass */
1048static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
1049{
1050 if (FDCS->reset) {
1051 reset_fdc(); /* do the reset during sleep to win time
1052 * if we don't need to sleep, it's a good
1053 * occasion anyways */
1054 return 1;
1055 }
1056
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001057 if (time_before(jiffies, delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 del_timer(&fd_timer);
1059 fd_timer.function = function;
1060 fd_timer.expires = delay;
1061 add_timer(&fd_timer);
1062 return 1;
1063 }
1064 return 0;
1065}
1066
1067static DEFINE_SPINLOCK(floppy_hlt_lock);
1068static int hlt_disabled;
1069static void floppy_disable_hlt(void)
1070{
1071 unsigned long flags;
1072
1073 spin_lock_irqsave(&floppy_hlt_lock, flags);
1074 if (!hlt_disabled) {
1075 hlt_disabled = 1;
1076#ifdef HAVE_DISABLE_HLT
1077 disable_hlt();
1078#endif
1079 }
1080 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1081}
1082
1083static void floppy_enable_hlt(void)
1084{
1085 unsigned long flags;
1086
1087 spin_lock_irqsave(&floppy_hlt_lock, flags);
1088 if (hlt_disabled) {
1089 hlt_disabled = 0;
1090#ifdef HAVE_DISABLE_HLT
1091 enable_hlt();
1092#endif
1093 }
1094 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1095}
1096
1097static void setup_DMA(void)
1098{
1099 unsigned long f;
1100
1101#ifdef FLOPPY_SANITY_CHECK
1102 if (raw_cmd->length == 0) {
1103 int i;
1104
Joe Perchesb46df352010-03-10 15:20:46 -08001105 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001107 pr_cont("%x,", raw_cmd->cmd[i]);
1108 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 cont->done(0);
1110 FDCS->reset = 1;
1111 return;
1112 }
1113 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001114 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 cont->done(0);
1116 FDCS->reset = 1;
1117 return;
1118 }
1119#endif
1120 f = claim_dma_lock();
1121 fd_disable_dma();
1122#ifdef fd_dma_setup
1123 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1124 (raw_cmd->flags & FD_RAW_READ) ?
1125 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1126 release_dma_lock(f);
1127 cont->done(0);
1128 FDCS->reset = 1;
1129 return;
1130 }
1131 release_dma_lock(f);
1132#else
1133 fd_clear_dma_ff();
1134 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1135 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1136 DMA_MODE_READ : DMA_MODE_WRITE);
1137 fd_set_dma_addr(raw_cmd->kernel_data);
1138 fd_set_dma_count(raw_cmd->length);
1139 virtual_dma_port = FDCS->address;
1140 fd_enable_dma();
1141 release_dma_lock(f);
1142#endif
1143 floppy_disable_hlt();
1144}
1145
1146static void show_floppy(void);
1147
1148/* waits until the fdc becomes ready */
1149static int wait_til_ready(void)
1150{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001151 int status;
1152 int counter;
1153
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 if (FDCS->reset)
1155 return -1;
1156 for (counter = 0; counter < 10000; counter++) {
1157 status = fd_inb(FD_STATUS);
1158 if (status & STATUS_READY)
1159 return status;
1160 }
1161 if (!initialising) {
1162 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1163 show_floppy();
1164 }
1165 FDCS->reset = 1;
1166 return -1;
1167}
1168
1169/* sends a command byte to the fdc */
1170static int output_byte(char byte)
1171{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001172 int status = wait_til_ready();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001174 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 return -1;
1176 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY) {
1177 fd_outb(byte, FD_DATA);
1178#ifdef FLOPPY_SANITY_CHECK
1179 output_log[output_log_pos].data = byte;
1180 output_log[output_log_pos].status = status;
1181 output_log[output_log_pos].jiffies = jiffies;
1182 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
1183#endif
1184 return 0;
1185 }
1186 FDCS->reset = 1;
1187 if (!initialising) {
1188 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1189 byte, fdc, status);
1190 show_floppy();
1191 }
1192 return -1;
1193}
1194
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195/* gets the response from the fdc */
1196static int result(void)
1197{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001198 int i;
1199 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200
1201 for (i = 0; i < MAX_REPLIES; i++) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001202 status = wait_til_ready();
1203 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 break;
1205 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1206 if ((status & ~STATUS_BUSY) == STATUS_READY) {
1207#ifdef FLOPPY_SANITY_CHECK
1208 resultjiffies = jiffies;
1209 resultsize = i;
1210#endif
1211 return i;
1212 }
1213 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1214 reply_buffer[i] = fd_inb(FD_DATA);
1215 else
1216 break;
1217 }
1218 if (!initialising) {
1219 DPRINT
1220 ("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1221 fdc, status, i);
1222 show_floppy();
1223 }
1224 FDCS->reset = 1;
1225 return -1;
1226}
1227
1228#define MORE_OUTPUT -2
1229/* does the fdc need more output? */
1230static int need_more_output(void)
1231{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001232 int status = wait_til_ready();
Jesper Juhl06f748c2007-10-16 23:30:57 -07001233
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001234 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 return -1;
1236 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY)
1237 return MORE_OUTPUT;
1238 return result();
1239}
1240
1241/* Set perpendicular mode as required, based on data rate, if supported.
1242 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1243 */
1244static inline void perpendicular_mode(void)
1245{
1246 unsigned char perp_mode;
1247
1248 if (raw_cmd->rate & 0x40) {
1249 switch (raw_cmd->rate & 3) {
1250 case 0:
1251 perp_mode = 2;
1252 break;
1253 case 3:
1254 perp_mode = 3;
1255 break;
1256 default:
1257 DPRINT("Invalid data rate for perpendicular mode!\n");
1258 cont->done(0);
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001259 FDCS->reset = 1;
1260 /*
1261 * convenient way to return to
1262 * redo without too much hassle
1263 * (deep stack et al.)
1264 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 return;
1266 }
1267 } else
1268 perp_mode = 0;
1269
1270 if (FDCS->perp_mode == perp_mode)
1271 return;
1272 if (FDCS->version >= FDC_82077_ORIG) {
1273 output_byte(FD_PERPENDICULAR);
1274 output_byte(perp_mode);
1275 FDCS->perp_mode = perp_mode;
1276 } else if (perp_mode) {
1277 DPRINT("perpendicular mode not supported by this FDC.\n");
1278 }
1279} /* perpendicular_mode */
1280
1281static int fifo_depth = 0xa;
1282static int no_fifo;
1283
1284static int fdc_configure(void)
1285{
1286 /* Turn on FIFO */
1287 output_byte(FD_CONFIGURE);
1288 if (need_more_output() != MORE_OUTPUT)
1289 return 0;
1290 output_byte(0);
1291 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1292 output_byte(0); /* pre-compensation from track
1293 0 upwards */
1294 return 1;
1295}
1296
1297#define NOMINAL_DTR 500
1298
1299/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1300 * head load time, and DMA disable flag to values needed by floppy.
1301 *
1302 * The value "dtr" is the data transfer rate in Kbps. It is needed
1303 * to account for the data rate-based scaling done by the 82072 and 82077
1304 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1305 * 8272a).
1306 *
1307 * Note that changing the data transfer rate has a (probably deleterious)
1308 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1309 * fdc_specify is called again after each data transfer rate
1310 * change.
1311 *
1312 * srt: 1000 to 16000 in microseconds
1313 * hut: 16 to 240 milliseconds
1314 * hlt: 2 to 254 milliseconds
1315 *
1316 * These values are rounded up to the next highest available delay time.
1317 */
1318static void fdc_specify(void)
1319{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001320 unsigned char spec1;
1321 unsigned char spec2;
1322 unsigned long srt;
1323 unsigned long hlt;
1324 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 unsigned long dtr = NOMINAL_DTR;
1326 unsigned long scale_dtr = NOMINAL_DTR;
1327 int hlt_max_code = 0x7f;
1328 int hut_max_code = 0xf;
1329
1330 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1331 fdc_configure();
1332 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 }
1334
1335 switch (raw_cmd->rate & 0x03) {
1336 case 3:
1337 dtr = 1000;
1338 break;
1339 case 1:
1340 dtr = 300;
1341 if (FDCS->version >= FDC_82078) {
1342 /* chose the default rate table, not the one
1343 * where 1 = 2 Mbps */
1344 output_byte(FD_DRIVESPEC);
1345 if (need_more_output() == MORE_OUTPUT) {
1346 output_byte(UNIT(current_drive));
1347 output_byte(0xc0);
1348 }
1349 }
1350 break;
1351 case 2:
1352 dtr = 250;
1353 break;
1354 }
1355
1356 if (FDCS->version >= FDC_82072) {
1357 scale_dtr = dtr;
1358 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1359 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1360 }
1361
1362 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001363 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001364 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001366
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 SUPBOUND(srt, 0xf);
1368 INFBOUND(srt, 0);
1369
Julia Lawall061837b2008-09-22 14:57:16 -07001370 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 if (hlt < 0x01)
1372 hlt = 0x01;
1373 else if (hlt > 0x7f)
1374 hlt = hlt_max_code;
1375
Julia Lawall061837b2008-09-22 14:57:16 -07001376 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 if (hut < 0x1)
1378 hut = 0x1;
1379 else if (hut > 0xf)
1380 hut = hut_max_code;
1381
1382 spec1 = (srt << 4) | hut;
1383 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1384
1385 /* If these parameters did not change, just return with success */
1386 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1387 /* Go ahead and set spec1 and spec2 */
1388 output_byte(FD_SPECIFY);
1389 output_byte(FDCS->spec1 = spec1);
1390 output_byte(FDCS->spec2 = spec2);
1391 }
1392} /* fdc_specify */
1393
1394/* Set the FDC's data transfer rate on behalf of the specified drive.
1395 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1396 * of the specify command (i.e. using the fdc_specify function).
1397 */
1398static int fdc_dtr(void)
1399{
1400 /* If data rate not already set to desired value, set it. */
1401 if ((raw_cmd->rate & 3) == FDCS->dtr)
1402 return 0;
1403
1404 /* Set dtr */
1405 fd_outb(raw_cmd->rate & 3, FD_DCR);
1406
1407 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1408 * need a stabilization period of several milliseconds to be
1409 * enforced after data rate changes before R/W operations.
1410 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1411 */
1412 FDCS->dtr = raw_cmd->rate & 3;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001413 return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
1414 (timeout_fn)floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415} /* fdc_dtr */
1416
1417static void tell_sector(void)
1418{
Joe Perchesb46df352010-03-10 15:20:46 -08001419 pr_cont(": track %d, head %d, sector %d, size %d",
1420 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421} /* tell_sector */
1422
Joe Perchesb46df352010-03-10 15:20:46 -08001423static void print_errors(void)
1424{
1425 DPRINT("");
1426 if (ST0 & ST0_ECE) {
1427 pr_cont("Recalibrate failed!");
1428 } else if (ST2 & ST2_CRC) {
1429 pr_cont("data CRC error");
1430 tell_sector();
1431 } else if (ST1 & ST1_CRC) {
1432 pr_cont("CRC error");
1433 tell_sector();
1434 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1435 (ST2 & ST2_MAM)) {
1436 if (!probing) {
1437 pr_cont("sector not found");
1438 tell_sector();
1439 } else
1440 pr_cont("probe failed...");
1441 } else if (ST2 & ST2_WC) { /* seek error */
1442 pr_cont("wrong cylinder");
1443 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1444 pr_cont("bad cylinder");
1445 } else {
1446 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1447 ST0, ST1, ST2);
1448 tell_sector();
1449 }
1450 pr_cont("\n");
1451}
1452
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453/*
1454 * OK, this error interpreting routine is called after a
1455 * DMA read/write has succeeded
1456 * or failed, so we check the results, and copy any buffers.
1457 * hhb: Added better error reporting.
1458 * ak: Made this into a separate routine.
1459 */
1460static int interpret_errors(void)
1461{
1462 char bad;
1463
1464 if (inr != 7) {
1465 DPRINT("-- FDC reply error");
1466 FDCS->reset = 1;
1467 return 1;
1468 }
1469
1470 /* check IC to find cause of interrupt */
1471 switch (ST0 & ST0_INTR) {
1472 case 0x40: /* error occurred during command execution */
1473 if (ST1 & ST1_EOC)
1474 return 0; /* occurs with pseudo-DMA */
1475 bad = 1;
1476 if (ST1 & ST1_WP) {
1477 DPRINT("Drive is write protected\n");
1478 CLEARF(FD_DISK_WRITABLE);
1479 cont->done(0);
1480 bad = 2;
1481 } else if (ST1 & ST1_ND) {
1482 SETF(FD_NEED_TWADDLE);
1483 } else if (ST1 & ST1_OR) {
1484 if (DP->flags & FTD_MSG)
1485 DPRINT("Over/Underrun - retrying\n");
1486 bad = 0;
1487 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001488 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 }
1490 if (ST2 & ST2_WC || ST2 & ST2_BC)
1491 /* wrong cylinder => recal */
1492 DRS->track = NEED_2_RECAL;
1493 return bad;
1494 case 0x80: /* invalid command given */
1495 DPRINT("Invalid FDC command given!\n");
1496 cont->done(0);
1497 return 2;
1498 case 0xc0:
1499 DPRINT("Abnormal termination caused by polling\n");
1500 cont->error();
1501 return 2;
1502 default: /* (0) Normal command termination */
1503 return 0;
1504 }
1505}
1506
1507/*
1508 * This routine is called when everything should be correctly set up
1509 * for the transfer (i.e. floppy motor is on, the correct floppy is
1510 * selected, and the head is sitting on the right track).
1511 */
1512static void setup_rw_floppy(void)
1513{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001514 int i;
1515 int r;
1516 int flags;
1517 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 unsigned long ready_date;
1519 timeout_fn function;
1520
1521 flags = raw_cmd->flags;
1522 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1523 flags |= FD_RAW_INTR;
1524
1525 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1526 ready_date = DRS->spinup_date + DP->spinup;
1527 /* If spinup will take a long time, rerun scandrives
1528 * again just before spinup completion. Beware that
1529 * after scandrives, we must again wait for selection.
1530 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001531 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 ready_date -= DP->select_delay;
Joe Perchesa0a52d62010-03-10 15:20:52 -08001533 function = (timeout_fn)floppy_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 } else
Joe Perchesa0a52d62010-03-10 15:20:52 -08001535 function = (timeout_fn)setup_rw_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536
1537 /* wait until the floppy is spinning fast enough */
1538 if (fd_wait_for_completion(ready_date, function))
1539 return;
1540 }
1541 dflags = DRS->flags;
1542
1543 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1544 setup_DMA();
1545
1546 if (flags & FD_RAW_INTR)
1547 do_floppy = main_command_interrupt;
1548
1549 r = 0;
1550 for (i = 0; i < raw_cmd->cmd_count; i++)
1551 r |= output_byte(raw_cmd->cmd[i]);
1552
1553 debugt("rw_command: ");
1554
1555 if (r) {
1556 cont->error();
1557 reset_fdc();
1558 return;
1559 }
1560
1561 if (!(flags & FD_RAW_INTR)) {
1562 inr = result();
1563 cont->interrupt();
1564 } else if (flags & FD_RAW_NEED_DISK)
1565 fd_watchdog();
1566}
1567
1568static int blind_seek;
1569
1570/*
1571 * This is the routine called after every seek (or recalibrate) interrupt
1572 * from the floppy controller.
1573 */
1574static void seek_interrupt(void)
1575{
1576 debugt("seek interrupt:");
1577 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1578 DPRINT("seek failed\n");
1579 DRS->track = NEED_2_RECAL;
1580 cont->error();
1581 cont->redo();
1582 return;
1583 }
1584 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
1585#ifdef DCL_DEBUG
1586 if (DP->flags & FD_DEBUG) {
Joe Perchesb46df352010-03-10 15:20:46 -08001587 DPRINT("clearing NEWCHANGE flag because of effective seek\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 DPRINT("jiffies=%lu\n", jiffies);
1589 }
1590#endif
1591 CLEARF(FD_DISK_NEWCHANGE); /* effective seek */
1592 DRS->select_date = jiffies;
1593 }
1594 DRS->track = ST1;
1595 floppy_ready();
1596}
1597
1598static void check_wp(void)
1599{
1600 if (TESTF(FD_VERIFY)) {
1601 /* check write protection */
1602 output_byte(FD_GETSTATUS);
1603 output_byte(UNIT(current_drive));
1604 if (result() != 1) {
1605 FDCS->reset = 1;
1606 return;
1607 }
1608 CLEARF(FD_VERIFY);
1609 CLEARF(FD_NEED_TWADDLE);
1610#ifdef DCL_DEBUG
1611 if (DP->flags & FD_DEBUG) {
1612 DPRINT("checking whether disk is write protected\n");
1613 DPRINT("wp=%x\n", ST3 & 0x40);
1614 }
1615#endif
1616 if (!(ST3 & 0x40))
1617 SETF(FD_DISK_WRITABLE);
1618 else
1619 CLEARF(FD_DISK_WRITABLE);
1620 }
1621}
1622
1623static void seek_floppy(void)
1624{
1625 int track;
1626
1627 blind_seek = 0;
1628
1629#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08001630 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 DPRINT("calling disk change from seek\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632#endif
1633
1634 if (!TESTF(FD_DISK_NEWCHANGE) &&
1635 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1636 /* the media changed flag should be cleared after the seek.
1637 * If it isn't, this means that there is really no disk in
1638 * the drive.
1639 */
1640 SETF(FD_DISK_CHANGED);
1641 cont->done(0);
1642 cont->redo();
1643 return;
1644 }
1645 if (DRS->track <= NEED_1_RECAL) {
1646 recalibrate_floppy();
1647 return;
1648 } else if (TESTF(FD_DISK_NEWCHANGE) &&
1649 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1650 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1651 /* we seek to clear the media-changed condition. Does anybody
1652 * know a more elegant way, which works on all drives? */
1653 if (raw_cmd->track)
1654 track = raw_cmd->track - 1;
1655 else {
1656 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1657 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1658 blind_seek = 1;
1659 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1660 }
1661 track = 1;
1662 }
1663 } else {
1664 check_wp();
1665 if (raw_cmd->track != DRS->track &&
1666 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1667 track = raw_cmd->track;
1668 else {
1669 setup_rw_floppy();
1670 return;
1671 }
1672 }
1673
1674 do_floppy = seek_interrupt;
1675 output_byte(FD_SEEK);
1676 output_byte(UNIT(current_drive));
Joe Perches2300f902010-03-10 15:20:49 -08001677 if (output_byte(track) < 0) {
1678 reset_fdc();
1679 return;
1680 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 debugt("seek command:");
1682}
1683
1684static void recal_interrupt(void)
1685{
1686 debugt("recal interrupt:");
1687 if (inr != 2)
1688 FDCS->reset = 1;
1689 else if (ST0 & ST0_ECE) {
1690 switch (DRS->track) {
1691 case NEED_1_RECAL:
1692 debugt("recal interrupt need 1 recal:");
1693 /* after a second recalibrate, we still haven't
1694 * reached track 0. Probably no drive. Raise an
1695 * error, as failing immediately might upset
1696 * computers possessed by the Devil :-) */
1697 cont->error();
1698 cont->redo();
1699 return;
1700 case NEED_2_RECAL:
1701 debugt("recal interrupt need 2 recal:");
1702 /* If we already did a recalibrate,
1703 * and we are not at track 0, this
1704 * means we have moved. (The only way
1705 * not to move at recalibration is to
1706 * be already at track 0.) Clear the
1707 * new change flag */
1708#ifdef DCL_DEBUG
Joe Perchesb46df352010-03-10 15:20:46 -08001709 if (DP->flags & FD_DEBUG)
1710 DPRINT("clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711#endif
1712
1713 CLEARF(FD_DISK_NEWCHANGE);
1714 DRS->select_date = jiffies;
1715 /* fall through */
1716 default:
1717 debugt("recal interrupt default:");
1718 /* Recalibrate moves the head by at
1719 * most 80 steps. If after one
1720 * recalibrate we don't have reached
1721 * track 0, this might mean that we
1722 * started beyond track 80. Try
1723 * again. */
1724 DRS->track = NEED_1_RECAL;
1725 break;
1726 }
1727 } else
1728 DRS->track = ST1;
1729 floppy_ready();
1730}
1731
1732static void print_result(char *message, int inr)
1733{
1734 int i;
1735
1736 DPRINT("%s ", message);
1737 if (inr >= 0)
1738 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001739 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1740 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741}
1742
1743/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001744irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 int do_print;
1747 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001748 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749
1750 lasthandler = handler;
1751 interruptjiffies = jiffies;
1752
1753 f = claim_dma_lock();
1754 fd_disable_dma();
1755 release_dma_lock(f);
1756
1757 floppy_enable_hlt();
1758 do_floppy = NULL;
1759 if (fdc >= N_FDC || FDCS->address == -1) {
1760 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001761 pr_info("DOR0=%x\n", fdc_state[0].dor);
1762 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
1763 pr_info("handler=%p\n", handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 is_alive("bizarre fdc");
1765 return IRQ_NONE;
1766 }
1767
1768 FDCS->reset = 0;
1769 /* We have to clear the reset flag here, because apparently on boxes
1770 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1771 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1772 * emission of the SENSEI's.
1773 * It is OK to emit floppy commands because we are in an interrupt
1774 * handler here, and thus we have to fear no interference of other
1775 * activity.
1776 */
1777
1778 do_print = !handler && print_unex && !initialising;
1779
1780 inr = result();
1781 if (do_print)
1782 print_result("unexpected interrupt", inr);
1783 if (inr == 0) {
1784 int max_sensei = 4;
1785 do {
1786 output_byte(FD_SENSEI);
1787 inr = result();
1788 if (do_print)
1789 print_result("sensei", inr);
1790 max_sensei--;
1791 } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2
1792 && max_sensei);
1793 }
1794 if (!handler) {
1795 FDCS->reset = 1;
1796 return IRQ_NONE;
1797 }
1798 schedule_bh(handler);
1799 is_alive("normal interrupt end");
1800
1801 /* FIXME! Was it really for us? */
1802 return IRQ_HANDLED;
1803}
1804
1805static void recalibrate_floppy(void)
1806{
1807 debugt("recalibrate floppy:");
1808 do_floppy = recal_interrupt;
1809 output_byte(FD_RECALIBRATE);
Joe Perches2300f902010-03-10 15:20:49 -08001810 if (output_byte(UNIT(current_drive)) < 0) {
1811 reset_fdc();
1812 return;
1813 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814}
1815
1816/*
1817 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1818 */
1819static void reset_interrupt(void)
1820{
1821 debugt("reset interrupt:");
1822 result(); /* get the status ready for set_fdc */
1823 if (FDCS->reset) {
Joe Perchesb46df352010-03-10 15:20:46 -08001824 pr_info("reset set in interrupt, calling %p\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 cont->error(); /* a reset just after a reset. BAD! */
1826 }
1827 cont->redo();
1828}
1829
1830/*
1831 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1832 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1833 */
1834static void reset_fdc(void)
1835{
1836 unsigned long flags;
1837
1838 do_floppy = reset_interrupt;
1839 FDCS->reset = 0;
1840 reset_fdc_info(0);
1841
1842 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1843 /* Irrelevant for systems with true DMA (i386). */
1844
1845 flags = claim_dma_lock();
1846 fd_disable_dma();
1847 release_dma_lock(flags);
1848
1849 if (FDCS->version >= FDC_82072A)
1850 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1851 else {
1852 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1853 udelay(FD_RESET_DELAY);
1854 fd_outb(FDCS->dor, FD_DOR);
1855 }
1856}
1857
1858static void show_floppy(void)
1859{
1860 int i;
1861
Joe Perchesb46df352010-03-10 15:20:46 -08001862 pr_info("\n");
1863 pr_info("floppy driver state\n");
1864 pr_info("-------------------\n");
1865 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%p\n",
1866 jiffies, interruptjiffies, jiffies - interruptjiffies,
1867 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868
1869#ifdef FLOPPY_SANITY_CHECK
Joe Perchesb46df352010-03-10 15:20:46 -08001870 pr_info("timeout_message=%s\n", timeout_message);
1871 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001873 pr_info("%2x %2x %lu\n",
1874 output_log[(i + output_log_pos) % OLOGSIZE].data,
1875 output_log[(i + output_log_pos) % OLOGSIZE].status,
1876 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1877 pr_info("last result at %lu\n", resultjiffies);
1878 pr_info("last redo_fd_request at %lu\n", lastredo);
1879 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1880 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881#endif
1882
Joe Perchesb46df352010-03-10 15:20:46 -08001883 pr_info("status=%x\n", fd_inb(FD_STATUS));
1884 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 if (do_floppy)
Joe Perchesb46df352010-03-10 15:20:46 -08001886 pr_info("do_floppy=%p\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001887 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08001888 pr_info("floppy_work.func=%p\n", floppy_work.func);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08001890 pr_info("fd_timer.function=%p\n", fd_timer.function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 if (timer_pending(&fd_timeout)) {
Joe Perchesb46df352010-03-10 15:20:46 -08001892 pr_info("timer_function=%p\n", fd_timeout.function);
1893 pr_info("expires=%lu\n", fd_timeout.expires - jiffies);
1894 pr_info("now=%lu\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 }
Joe Perchesb46df352010-03-10 15:20:46 -08001896 pr_info("cont=%p\n", cont);
1897 pr_info("current_req=%p\n", current_req);
1898 pr_info("command_status=%d\n", command_status);
1899 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900}
1901
1902static void floppy_shutdown(unsigned long data)
1903{
1904 unsigned long flags;
1905
1906 if (!initialising)
1907 show_floppy();
1908 cancel_activity();
1909
1910 floppy_enable_hlt();
1911
1912 flags = claim_dma_lock();
1913 fd_disable_dma();
1914 release_dma_lock(flags);
1915
1916 /* avoid dma going to a random drive after shutdown */
1917
1918 if (!initialising)
1919 DPRINT("floppy timeout called\n");
1920 FDCS->reset = 1;
1921 if (cont) {
1922 cont->done(0);
1923 cont->redo(); /* this will recall reset when needed */
1924 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001925 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 process_fd_request();
1927 }
1928 is_alive("floppy shutdown");
1929}
1930
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001932static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001934 int mask;
1935 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936
1937 mask = 0xfc;
1938 data = UNIT(current_drive);
1939 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1940 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1941 set_debugt();
1942 /* no read since this drive is running */
1943 DRS->first_read_date = 0;
1944 /* note motor start time if motor is not yet running */
1945 DRS->spinup_date = jiffies;
1946 data |= (0x10 << UNIT(current_drive));
1947 }
1948 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1949 mask &= ~(0x10 << UNIT(current_drive));
1950
1951 /* starts motor and selects floppy */
1952 del_timer(motor_off_timer + current_drive);
1953 set_dor(fdc, mask, data);
1954
1955 /* wait_for_completion also schedules reset if needed. */
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001956 return fd_wait_for_completion(DRS->select_date + DP->select_delay,
1957 (timeout_fn)function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958}
1959
1960static void floppy_ready(void)
1961{
Joe Perches045f9832010-03-10 15:20:47 -08001962 if (FDCS->reset) {
1963 reset_fdc();
1964 return;
1965 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 if (start_motor(floppy_ready))
1967 return;
1968 if (fdc_dtr())
1969 return;
1970
1971#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08001972 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 DPRINT("calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974#endif
1975 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1976 disk_change(current_drive) && !DP->select_delay)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001977 twaddle(); /* this clears the dcl on certain
1978 * drive/controller combinations */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979
1980#ifdef fd_chose_dma_mode
1981 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1982 unsigned long flags = claim_dma_lock();
1983 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1984 release_dma_lock(flags);
1985 }
1986#endif
1987
1988 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1989 perpendicular_mode();
1990 fdc_specify(); /* must be done here because of hut, hlt ... */
1991 seek_floppy();
1992 } else {
1993 if ((raw_cmd->flags & FD_RAW_READ) ||
1994 (raw_cmd->flags & FD_RAW_WRITE))
1995 fdc_specify();
1996 setup_rw_floppy();
1997 }
1998}
1999
2000static void floppy_start(void)
2001{
2002 reschedule_timeout(current_reqD, "floppy start", 0);
2003
2004 scandrives();
2005#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08002006 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 DPRINT("setting NEWCHANGE in floppy_start\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008#endif
2009 SETF(FD_DISK_NEWCHANGE);
2010 floppy_ready();
2011}
2012
2013/*
2014 * ========================================================================
2015 * here ends the bottom half. Exported routines are:
2016 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
2017 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
2018 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
2019 * and set_dor.
2020 * ========================================================================
2021 */
2022/*
2023 * General purpose continuations.
2024 * ==============================
2025 */
2026
2027static void do_wakeup(void)
2028{
2029 reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);
2030 cont = NULL;
2031 command_status += 2;
2032 wake_up(&command_done);
2033}
2034
2035static struct cont_t wakeup_cont = {
2036 .interrupt = empty,
2037 .redo = do_wakeup,
2038 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002039 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040};
2041
2042static struct cont_t intr_cont = {
2043 .interrupt = empty,
2044 .redo = process_fd_request,
2045 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002046 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047};
2048
Jesper Juhl06f748c2007-10-16 23:30:57 -07002049static int wait_til_done(void (*handler)(void), int interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050{
2051 int ret;
2052
2053 schedule_bh(handler);
2054
2055 if (command_status < 2 && NO_SIGNAL) {
2056 DECLARE_WAITQUEUE(wait, current);
2057
2058 add_wait_queue(&command_done, &wait);
2059 for (;;) {
2060 set_current_state(interruptible ?
2061 TASK_INTERRUPTIBLE :
2062 TASK_UNINTERRUPTIBLE);
2063
2064 if (command_status >= 2 || !NO_SIGNAL)
2065 break;
2066
2067 is_alive("wait_til_done");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 schedule();
2069 }
2070
2071 set_current_state(TASK_RUNNING);
2072 remove_wait_queue(&command_done, &wait);
2073 }
2074
2075 if (command_status < 2) {
2076 cancel_activity();
2077 cont = &intr_cont;
2078 reset_fdc();
2079 return -EINTR;
2080 }
2081
2082 if (FDCS->reset)
2083 command_status = FD_COMMAND_ERROR;
2084 if (command_status == FD_COMMAND_OKAY)
2085 ret = 0;
2086 else
2087 ret = -EIO;
2088 command_status = FD_COMMAND_NONE;
2089 return ret;
2090}
2091
2092static void generic_done(int result)
2093{
2094 command_status = result;
2095 cont = &wakeup_cont;
2096}
2097
2098static void generic_success(void)
2099{
2100 cont->done(1);
2101}
2102
2103static void generic_failure(void)
2104{
2105 cont->done(0);
2106}
2107
2108static void success_and_wakeup(void)
2109{
2110 generic_success();
2111 cont->redo();
2112}
2113
2114/*
2115 * formatting and rw support.
2116 * ==========================
2117 */
2118
2119static int next_valid_format(void)
2120{
2121 int probed_format;
2122
2123 probed_format = DRS->probed_format;
2124 while (1) {
2125 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2126 DRS->probed_format = 0;
2127 return 1;
2128 }
2129 if (floppy_type[DP->autodetect[probed_format]].sect) {
2130 DRS->probed_format = probed_format;
2131 return 0;
2132 }
2133 probed_format++;
2134 }
2135}
2136
2137static void bad_flp_intr(void)
2138{
2139 int err_count;
2140
2141 if (probing) {
2142 DRS->probed_format++;
2143 if (!next_valid_format())
2144 return;
2145 }
2146 err_count = ++(*errors);
2147 INFBOUND(DRWE->badness, err_count);
2148 if (err_count > DP->max_errors.abort)
2149 cont->done(0);
2150 if (err_count > DP->max_errors.reset)
2151 FDCS->reset = 1;
2152 else if (err_count > DP->max_errors.recal)
2153 DRS->track = NEED_2_RECAL;
2154}
2155
2156static void set_floppy(int drive)
2157{
2158 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002159
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 if (type)
2161 _floppy = floppy_type + type;
2162 else
2163 _floppy = current_type[drive];
2164}
2165
2166/*
2167 * formatting support.
2168 * ===================
2169 */
2170static void format_interrupt(void)
2171{
2172 switch (interpret_errors()) {
2173 case 1:
2174 cont->error();
2175 case 2:
2176 break;
2177 case 0:
2178 cont->done(1);
2179 }
2180 cont->redo();
2181}
2182
2183#define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2)
Joe Perches48c8cee2010-03-10 15:20:45 -08002184#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002186
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187static void setup_format_params(int track)
2188{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002189 int n;
2190 int il;
2191 int count;
2192 int head_shift;
2193 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 struct fparm {
2195 unsigned char track, head, sect, size;
2196 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197
2198 raw_cmd = &default_raw_cmd;
2199 raw_cmd->track = track;
2200
Joe Perches48c8cee2010-03-10 15:20:45 -08002201 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2202 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 raw_cmd->rate = _floppy->rate & 0x43;
2204 raw_cmd->cmd_count = NR_F;
2205 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2206 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2207 F_SIZECODE = FD_SIZECODE(_floppy);
2208 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2209 F_GAP = _floppy->fmt_gap;
2210 F_FILL = FD_FILL_BYTE;
2211
2212 raw_cmd->kernel_data = floppy_track_buffer;
2213 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2214
2215 /* allow for about 30ms for data transport per track */
2216 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2217
2218 /* a ``cylinder'' is two tracks plus a little stepping time */
2219 track_shift = 2 * head_shift + 3;
2220
2221 /* position of logical sector 1 on this track */
2222 n = (track_shift * format_req.track + head_shift * format_req.head)
2223 % F_SECT_PER_TRACK;
2224
2225 /* determine interleave */
2226 il = 1;
2227 if (_floppy->fmt_gap < 0x22)
2228 il++;
2229
2230 /* initialize field */
2231 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2232 here[count].track = format_req.track;
2233 here[count].head = format_req.head;
2234 here[count].sect = 0;
2235 here[count].size = F_SIZECODE;
2236 }
2237 /* place logical sectors */
2238 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2239 here[n].sect = count;
2240 n = (n + il) % F_SECT_PER_TRACK;
2241 if (here[n].sect) { /* sector busy, find next free sector */
2242 ++n;
2243 if (n >= F_SECT_PER_TRACK) {
2244 n -= F_SECT_PER_TRACK;
2245 while (here[n].sect)
2246 ++n;
2247 }
2248 }
2249 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002250 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002252 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 }
2254}
2255
2256static void redo_format(void)
2257{
2258 buffer_track = -1;
2259 setup_format_params(format_req.track << STRETCH(_floppy));
2260 floppy_start();
2261 debugt("queue format request");
2262}
2263
2264static struct cont_t format_cont = {
2265 .interrupt = format_interrupt,
2266 .redo = redo_format,
2267 .error = bad_flp_intr,
2268 .done = generic_done
2269};
2270
2271static int do_format(int drive, struct format_descr *tmp_format_req)
2272{
2273 int ret;
2274
Joe Perches52a0d612010-03-10 15:20:53 -08002275 if (lock_fdc(drive, 1))
2276 return -EINTR;
2277
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 set_floppy(drive);
2279 if (!_floppy ||
2280 _floppy->track > DP->tracks ||
2281 tmp_format_req->track >= _floppy->track ||
2282 tmp_format_req->head >= _floppy->head ||
2283 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2284 !_floppy->fmt_gap) {
2285 process_fd_request();
2286 return -EINVAL;
2287 }
2288 format_req = *tmp_format_req;
2289 format_errors = 0;
2290 cont = &format_cont;
2291 errors = &format_errors;
2292 IWAIT(redo_format);
2293 process_fd_request();
2294 return ret;
2295}
2296
2297/*
2298 * Buffer read/write and support
2299 * =============================
2300 */
2301
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002302static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303{
2304 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002305 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306
2307 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002308 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002309 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002310 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312
2313 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002314 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 current_req = NULL;
2316}
2317
2318/* new request_done. Can handle physical sectors which are smaller than a
2319 * logical buffer */
2320static void request_done(int uptodate)
2321{
2322 struct request_queue *q = floppy_queue;
2323 struct request *req = current_req;
2324 unsigned long flags;
2325 int block;
2326
2327 probing = 0;
Joe Perchesb46df352010-03-10 15:20:46 -08002328 reschedule_timeout(MAXTIMEOUT, "request done", uptodate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329
2330 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002331 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 return;
2333 }
2334
2335 if (uptodate) {
2336 /* maintain values for invalidation on geometry
2337 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002338 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 INFBOUND(DRS->maxblock, block);
2340 if (block > _floppy->sect)
2341 DRS->maxtrack = 1;
2342
2343 /* unlock chained buffers */
2344 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002345 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 spin_unlock_irqrestore(q->queue_lock, flags);
2347 } else {
2348 if (rq_data_dir(req) == WRITE) {
2349 /* record write error information */
2350 DRWE->write_errors++;
2351 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002352 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 DRWE->first_error_generation = DRS->generation;
2354 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002355 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 DRWE->last_error_generation = DRS->generation;
2357 }
2358 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002359 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 spin_unlock_irqrestore(q->queue_lock, flags);
2361 }
2362}
2363
2364/* Interrupt handler evaluating the result of the r/w operation */
2365static void rw_interrupt(void)
2366{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002367 int eoc;
2368 int ssize;
2369 int heads;
2370 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371
2372 if (R_HEAD >= 2) {
2373 /* some Toshiba floppy controllers occasionnally seem to
2374 * return bogus interrupts after read/write operations, which
2375 * can be recognized by a bad head number (>= 2) */
2376 return;
2377 }
2378
2379 if (!DRS->first_read_date)
2380 DRS->first_read_date = jiffies;
2381
2382 nr_sectors = 0;
2383 CODE2SIZE;
2384
2385 if (ST1 & ST1_EOC)
2386 eoc = 1;
2387 else
2388 eoc = 0;
2389
2390 if (COMMAND & 0x80)
2391 heads = 2;
2392 else
2393 heads = 1;
2394
2395 nr_sectors = (((R_TRACK - TRACK) * heads +
2396 R_HEAD - HEAD) * SECT_PER_TRACK +
2397 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2398
2399#ifdef FLOPPY_SANITY_CHECK
2400 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002401 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 DPRINT("long rw: %x instead of %lx\n",
2403 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002404 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2405 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2406 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2407 pr_info("heads=%d eoc=%d\n", heads, eoc);
2408 pr_info("spt=%d st=%d ss=%d\n",
2409 SECT_PER_TRACK, fsector_t, ssize);
2410 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 }
2412#endif
2413
2414 nr_sectors -= in_sector_offset;
2415 INFBOUND(nr_sectors, 0);
2416 SUPBOUND(current_count_sectors, nr_sectors);
2417
2418 switch (interpret_errors()) {
2419 case 2:
2420 cont->redo();
2421 return;
2422 case 1:
2423 if (!current_count_sectors) {
2424 cont->error();
2425 cont->redo();
2426 return;
2427 }
2428 break;
2429 case 0:
2430 if (!current_count_sectors) {
2431 cont->redo();
2432 return;
2433 }
2434 current_type[current_drive] = _floppy;
2435 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2436 break;
2437 }
2438
2439 if (probing) {
2440 if (DP->flags & FTD_MSG)
2441 DPRINT("Auto-detected floppy type %s in fd%d\n",
2442 _floppy->name, current_drive);
2443 current_type[current_drive] = _floppy;
2444 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2445 probing = 0;
2446 }
2447
2448 if (CT(COMMAND) != FD_READ ||
2449 raw_cmd->kernel_data == current_req->buffer) {
2450 /* transfer directly from buffer */
2451 cont->done(1);
2452 } else if (CT(COMMAND) == FD_READ) {
2453 buffer_track = raw_cmd->track;
2454 buffer_drive = current_drive;
2455 INFBOUND(buffer_max, nr_sectors + fsector_t);
2456 }
2457 cont->redo();
2458}
2459
2460/* Compute maximal contiguous buffer size. */
2461static int buffer_chain_size(void)
2462{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 struct bio_vec *bv;
NeilBrown5705f702007-09-25 12:35:59 +02002464 int size;
2465 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 char *base;
2467
2468 base = bio_data(current_req->bio);
2469 size = 0;
2470
NeilBrown5705f702007-09-25 12:35:59 +02002471 rq_for_each_segment(bv, current_req, iter) {
2472 if (page_address(bv->bv_page) + bv->bv_offset != base + size)
2473 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474
NeilBrown5705f702007-09-25 12:35:59 +02002475 size += bv->bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 }
2477
2478 return size >> 9;
2479}
2480
2481/* Compute the maximal transfer size */
2482static int transfer_size(int ssize, int max_sector, int max_size)
2483{
2484 SUPBOUND(max_sector, fsector_t + max_size);
2485
2486 /* alignment */
2487 max_sector -= (max_sector % _floppy->sect) % ssize;
2488
2489 /* transfer size, beginning not aligned */
2490 current_count_sectors = max_sector - fsector_t;
2491
2492 return max_sector;
2493}
2494
2495/*
2496 * Move data from/to the track buffer to/from the buffer cache.
2497 */
2498static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2499{
2500 int remaining; /* number of transferred 512-byte sectors */
2501 struct bio_vec *bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002502 char *buffer;
2503 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002504 int size;
2505 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506
2507 max_sector = transfer_size(ssize,
2508 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002509 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510
2511 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002512 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002514 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
2516 remaining = current_count_sectors << 9;
2517#ifdef FLOPPY_SANITY_CHECK
Tejun Heo1011c1b2009-05-07 22:24:45 +09002518 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002520 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2521 pr_info("remaining=%d\n", remaining >> 9);
2522 pr_info("current_req->nr_sectors=%u\n",
2523 blk_rq_sectors(current_req));
2524 pr_info("current_req->current_nr_sectors=%u\n",
2525 blk_rq_cur_sectors(current_req));
2526 pr_info("max_sector=%d\n", max_sector);
2527 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 }
2529#endif
2530
2531 buffer_max = max(max_sector, buffer_max);
2532
2533 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2534
Tejun Heo1011c1b2009-05-07 22:24:45 +09002535 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536
NeilBrown5705f702007-09-25 12:35:59 +02002537 rq_for_each_segment(bv, current_req, iter) {
2538 if (!remaining)
2539 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540
NeilBrown5705f702007-09-25 12:35:59 +02002541 size = bv->bv_len;
2542 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543
NeilBrown5705f702007-09-25 12:35:59 +02002544 buffer = page_address(bv->bv_page) + bv->bv_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545#ifdef FLOPPY_SANITY_CHECK
NeilBrown5705f702007-09-25 12:35:59 +02002546 if (dma_buffer + size >
2547 floppy_track_buffer + (max_buffer_sectors << 10) ||
2548 dma_buffer < floppy_track_buffer) {
2549 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002550 (int)((floppy_track_buffer - dma_buffer) >> 9));
2551 pr_info("fsector_t=%d buffer_min=%d\n",
2552 fsector_t, buffer_min);
2553 pr_info("current_count_sectors=%ld\n",
2554 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002556 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002557 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002558 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002559 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 }
NeilBrown5705f702007-09-25 12:35:59 +02002561 if (((unsigned long)buffer) % 512)
2562 DPRINT("%p buffer not aligned\n", buffer);
2563#endif
2564 if (CT(COMMAND) == FD_READ)
2565 memcpy(buffer, dma_buffer, size);
2566 else
2567 memcpy(dma_buffer, buffer, size);
2568
2569 remaining -= size;
2570 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 }
2572#ifdef FLOPPY_SANITY_CHECK
2573 if (remaining) {
2574 if (remaining > 0)
2575 max_sector -= remaining >> 9;
2576 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2577 }
2578#endif
2579}
2580
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581/* work around a bug in pseudo DMA
2582 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2583 * sending data. Hence we need a different way to signal the
2584 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2585 * does not work with MT, hence we can only transfer one head at
2586 * a time
2587 */
2588static void virtualdmabug_workaround(void)
2589{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002590 int hard_sectors;
2591 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592
2593 if (CT(COMMAND) == FD_WRITE) {
2594 COMMAND &= ~0x80; /* switch off multiple track mode */
2595
2596 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2597 end_sector = SECTOR + hard_sectors - 1;
2598#ifdef FLOPPY_SANITY_CHECK
2599 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002600 pr_info("too many sectors %d > %d\n",
2601 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 return;
2603 }
2604#endif
Joe Perches48c8cee2010-03-10 15:20:45 -08002605 SECT_PER_TRACK = end_sector;
2606 /* make sure SECT_PER_TRACK
2607 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 }
2609}
2610
2611/*
2612 * Formulate a read/write request.
2613 * this routine decides where to load the data (directly to buffer, or to
2614 * tmp floppy area), how much data to load (the size of the buffer, the whole
2615 * track, or a single sector)
2616 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2617 * allocation on the fly, it should be done here. No other part should need
2618 * modification.
2619 */
2620
2621static int make_raw_rw_request(void)
2622{
2623 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002624 int max_sector;
2625 int max_size;
2626 int tracksize;
2627 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628
2629 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002630 pr_info("VFS: Block I/O scheduled on unopened device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 return 0;
2632 }
2633
2634 set_fdc((long)current_req->rq_disk->private_data);
2635
2636 raw_cmd = &default_raw_cmd;
2637 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
2638 FD_RAW_NEED_SEEK;
2639 raw_cmd->cmd_count = NR_RW;
2640 if (rq_data_dir(current_req) == READ) {
2641 raw_cmd->flags |= FD_RAW_READ;
2642 COMMAND = FM_MODE(_floppy, FD_READ);
2643 } else if (rq_data_dir(current_req) == WRITE) {
2644 raw_cmd->flags |= FD_RAW_WRITE;
2645 COMMAND = FM_MODE(_floppy, FD_WRITE);
2646 } else {
2647 DPRINT("make_raw_rw_request: unknown command\n");
2648 return 0;
2649 }
2650
2651 max_sector = _floppy->sect * _floppy->head;
2652
Tejun Heo83096eb2009-05-07 22:24:39 +09002653 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2654 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002656 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 current_count_sectors = 1;
2658 return 1;
2659 } else
2660 return 0;
2661 }
2662 HEAD = fsector_t / _floppy->sect;
2663
Keith Wansbrough9e491842008-09-22 14:57:17 -07002664 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 TESTF(FD_NEED_TWADDLE)) && fsector_t < _floppy->sect)
2666 max_sector = _floppy->sect;
2667
2668 /* 2M disks have phantom sectors on the first track */
2669 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2670 max_sector = 2 * _floppy->sect / 3;
2671 if (fsector_t >= max_sector) {
2672 current_count_sectors =
2673 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002674 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 return 1;
2676 }
2677 SIZECODE = 2;
2678 } else
2679 SIZECODE = FD_SIZECODE(_floppy);
2680 raw_cmd->rate = _floppy->rate & 0x43;
2681 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2682 raw_cmd->rate = 1;
2683
2684 if (SIZECODE)
2685 SIZECODE2 = 0xff;
2686 else
2687 SIZECODE2 = 0x80;
2688 raw_cmd->track = TRACK << STRETCH(_floppy);
2689 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2690 GAP = _floppy->gap;
2691 CODE2SIZE;
2692 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2693 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002694 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695
2696 /* tracksize describes the size which can be filled up with sectors
2697 * of size ssize.
2698 */
2699 tracksize = _floppy->sect - _floppy->sect % ssize;
2700 if (tracksize < _floppy->sect) {
2701 SECT_PER_TRACK++;
2702 if (tracksize <= fsector_t % _floppy->sect)
2703 SECTOR--;
2704
2705 /* if we are beyond tracksize, fill up using smaller sectors */
2706 while (tracksize <= fsector_t % _floppy->sect) {
2707 while (tracksize + ssize > _floppy->sect) {
2708 SIZECODE--;
2709 ssize >>= 1;
2710 }
2711 SECTOR++;
2712 SECT_PER_TRACK++;
2713 tracksize += ssize;
2714 }
2715 max_sector = HEAD * _floppy->sect + tracksize;
2716 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2717 max_sector = _floppy->sect;
2718 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2719 /* for virtual DMA bug workaround */
2720 max_sector = _floppy->sect;
2721 }
2722
2723 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2724 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002725 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 if ((raw_cmd->track == buffer_track) &&
2727 (current_drive == buffer_drive) &&
2728 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2729 /* data already in track buffer */
2730 if (CT(COMMAND) == FD_READ) {
2731 copy_buffer(1, max_sector, buffer_max);
2732 return 1;
2733 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002734 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 if (CT(COMMAND) == FD_WRITE) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002736 unsigned int sectors;
2737
2738 sectors = fsector_t + blk_rq_sectors(current_req);
2739 if (sectors > ssize && sectors < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 max_size = ssize + ssize;
2741 else
2742 max_size = ssize;
2743 }
2744 raw_cmd->flags &= ~FD_RAW_WRITE;
2745 raw_cmd->flags |= FD_RAW_READ;
2746 COMMAND = FM_MODE(_floppy, FD_READ);
2747 } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) {
2748 unsigned long dma_limit;
2749 int direct, indirect;
2750
2751 indirect =
2752 transfer_size(ssize, max_sector,
2753 max_buffer_sectors * 2) - fsector_t;
2754
2755 /*
2756 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2757 * on a 64 bit machine!
2758 */
2759 max_size = buffer_chain_size();
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002760 dma_limit = (MAX_DMA_ADDRESS -
2761 ((unsigned long)current_req->buffer)) >> 9;
Joe Perchesa81ee542010-03-10 15:20:46 -08002762 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 /* 64 kb boundaries */
2765 if (CROSS_64KB(current_req->buffer, max_size << 9))
2766 max_size = (K_64 -
2767 ((unsigned long)current_req->buffer) %
2768 K_64) >> 9;
2769 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2770 /*
2771 * We try to read tracks, but if we get too many errors, we
2772 * go back to reading just one sector at a time.
2773 *
2774 * This means we should be able to read a sector even if there
2775 * are other bad sectors on this track.
2776 */
2777 if (!direct ||
2778 (indirect * 2 > direct * 3 &&
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002779 *errors < DP->max_errors.read_track &&
2780 ((!probing ||
2781 (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002782 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 } else {
2784 raw_cmd->kernel_data = current_req->buffer;
2785 raw_cmd->length = current_count_sectors << 9;
2786 if (raw_cmd->length == 0) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002787 DPRINT("zero dma transfer attempted from make_raw_request\n");
2788 DPRINT("indirect=%d direct=%d fsector_t=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 indirect, direct, fsector_t);
2790 return 0;
2791 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 virtualdmabug_workaround();
2793 return 2;
2794 }
2795 }
2796
2797 if (CT(COMMAND) == FD_READ)
2798 max_size = max_sector; /* unbounded */
2799
2800 /* claim buffer track if needed */
2801 if (buffer_track != raw_cmd->track || /* bad track */
2802 buffer_drive != current_drive || /* bad drive */
2803 fsector_t > buffer_max ||
2804 fsector_t < buffer_min ||
2805 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002806 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 max_sector > 2 * max_buffer_sectors + buffer_min &&
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002808 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
2809 /* not enough space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 buffer_track = -1;
2811 buffer_drive = current_drive;
2812 buffer_max = buffer_min = aligned_sector_t;
2813 }
2814 raw_cmd->kernel_data = floppy_track_buffer +
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002815 ((aligned_sector_t - buffer_min) << 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816
2817 if (CT(COMMAND) == FD_WRITE) {
2818 /* copy write buffer to track buffer.
2819 * if we get here, we know that the write
2820 * is either aligned or the data already in the buffer
2821 * (buffer will be overwritten) */
2822#ifdef FLOPPY_SANITY_CHECK
2823 if (in_sector_offset && buffer_track == -1)
2824 DPRINT("internal error offset !=0 on write\n");
2825#endif
2826 buffer_track = raw_cmd->track;
2827 buffer_drive = current_drive;
2828 copy_buffer(ssize, max_sector,
2829 2 * max_buffer_sectors + buffer_min);
2830 } else
2831 transfer_size(ssize, max_sector,
2832 2 * max_buffer_sectors + buffer_min -
2833 aligned_sector_t);
2834
2835 /* round up current_count_sectors to get dma xfer size */
2836 raw_cmd->length = in_sector_offset + current_count_sectors;
2837 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2838 raw_cmd->length <<= 9;
2839#ifdef FLOPPY_SANITY_CHECK
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 if ((raw_cmd->length < current_count_sectors << 9) ||
2841 (raw_cmd->kernel_data != current_req->buffer &&
2842 CT(COMMAND) == FD_WRITE &&
2843 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2844 aligned_sector_t < buffer_min)) ||
2845 raw_cmd->length % (128 << SIZECODE) ||
2846 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2847 DPRINT("fractionary current count b=%lx s=%lx\n",
2848 raw_cmd->length, current_count_sectors);
2849 if (raw_cmd->kernel_data != current_req->buffer)
Joe Perchesb46df352010-03-10 15:20:46 -08002850 pr_info("addr=%d, length=%ld\n",
2851 (int)((raw_cmd->kernel_data -
2852 floppy_track_buffer) >> 9),
2853 current_count_sectors);
2854 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2855 fsector_t, aligned_sector_t, max_sector, max_size);
2856 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2857 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2858 COMMAND, SECTOR, HEAD, TRACK);
2859 pr_info("buffer drive=%d\n", buffer_drive);
2860 pr_info("buffer track=%d\n", buffer_track);
2861 pr_info("buffer_min=%d\n", buffer_min);
2862 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 return 0;
2864 }
2865
2866 if (raw_cmd->kernel_data != current_req->buffer) {
2867 if (raw_cmd->kernel_data < floppy_track_buffer ||
2868 current_count_sectors < 0 ||
2869 raw_cmd->length < 0 ||
2870 raw_cmd->kernel_data + raw_cmd->length >
2871 floppy_track_buffer + (max_buffer_sectors << 10)) {
2872 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002873 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2874 fsector_t, buffer_min, raw_cmd->length >> 9);
2875 pr_info("current_count_sectors=%ld\n",
2876 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002878 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002880 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 return 0;
2882 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002883 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002884 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 DPRINT("buffer overrun in direct transfer\n");
2886 return 0;
2887 } else if (raw_cmd->length < current_count_sectors << 9) {
2888 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002889 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2890 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 }
2892 if (raw_cmd->length == 0) {
2893 DPRINT("zero dma transfer attempted from make_raw_request\n");
2894 return 0;
2895 }
2896#endif
2897
2898 virtualdmabug_workaround();
2899 return 2;
2900}
2901
2902static void redo_fd_request(void)
2903{
2904#define REPEAT {request_done(0); continue; }
2905 int drive;
2906 int tmp;
2907
2908 lastredo = jiffies;
2909 if (current_drive < N_DRIVE)
2910 floppy_off(current_drive);
2911
2912 for (;;) {
2913 if (!current_req) {
2914 struct request *req;
2915
2916 spin_lock_irq(floppy_queue->queue_lock);
Tejun Heo9934c8c2009-05-08 11:54:16 +09002917 req = blk_fetch_request(floppy_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 spin_unlock_irq(floppy_queue->queue_lock);
2919 if (!req) {
2920 do_floppy = NULL;
2921 unlock_fdc();
2922 return;
2923 }
2924 current_req = req;
2925 }
2926 drive = (long)current_req->rq_disk->private_data;
2927 set_fdc(drive);
2928 reschedule_timeout(current_reqD, "redo fd request", 0);
2929
2930 set_floppy(drive);
2931 raw_cmd = &default_raw_cmd;
2932 raw_cmd->flags = 0;
2933 if (start_motor(redo_fd_request))
2934 return;
2935 disk_change(current_drive);
2936 if (test_bit(current_drive, &fake_change) ||
2937 TESTF(FD_DISK_CHANGED)) {
2938 DPRINT("disk absent or changed during operation\n");
2939 REPEAT;
2940 }
2941 if (!_floppy) { /* Autodetection */
2942 if (!probing) {
2943 DRS->probed_format = 0;
2944 if (next_valid_format()) {
2945 DPRINT("no autodetectable formats\n");
2946 _floppy = NULL;
2947 REPEAT;
2948 }
2949 }
2950 probing = 1;
2951 _floppy =
2952 floppy_type + DP->autodetect[DRS->probed_format];
2953 } else
2954 probing = 0;
2955 errors = &(current_req->errors);
2956 tmp = make_raw_rw_request();
2957 if (tmp < 2) {
2958 request_done(tmp);
2959 continue;
2960 }
2961
2962 if (TESTF(FD_NEED_TWADDLE))
2963 twaddle();
2964 schedule_bh(floppy_start);
2965 debugt("queue fd request");
2966 return;
2967 }
2968#undef REPEAT
2969}
2970
2971static struct cont_t rw_cont = {
2972 .interrupt = rw_interrupt,
2973 .redo = redo_fd_request,
2974 .error = bad_flp_intr,
2975 .done = request_done
2976};
2977
2978static void process_fd_request(void)
2979{
2980 cont = &rw_cont;
2981 schedule_bh(redo_fd_request);
2982}
2983
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002984static void do_fd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985{
2986 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002987 pr_info("VFS: do_fd_request called on non-open device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 return;
2989 }
2990
2991 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002992 pr_info("warning: usage count=0, current_req=%p exiting\n",
2993 current_req);
2994 pr_info("sect=%ld type=%x flags=%x\n",
2995 (long)blk_rq_pos(current_req), current_req->cmd_type,
2996 current_req->cmd_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 return;
2998 }
2999 if (test_bit(0, &fdc_busy)) {
3000 /* fdc busy, this new request will be treated when the
3001 current one is done */
3002 is_alive("do fd request, old request running");
3003 return;
3004 }
3005 lock_fdc(MAXTIMEOUT, 0);
3006 process_fd_request();
3007 is_alive("do fd request");
3008}
3009
3010static struct cont_t poll_cont = {
3011 .interrupt = success_and_wakeup,
3012 .redo = floppy_ready,
3013 .error = generic_failure,
3014 .done = generic_done
3015};
3016
3017static int poll_drive(int interruptible, int flag)
3018{
3019 int ret;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003020
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 /* no auto-sense, just clear dcl */
3022 raw_cmd = &default_raw_cmd;
3023 raw_cmd->flags = flag;
3024 raw_cmd->track = 0;
3025 raw_cmd->cmd_count = 0;
3026 cont = &poll_cont;
3027#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08003028 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 DPRINT("setting NEWCHANGE in poll_drive\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030#endif
3031 SETF(FD_DISK_NEWCHANGE);
3032 WAIT(floppy_ready);
3033 return ret;
3034}
3035
3036/*
3037 * User triggered reset
3038 * ====================
3039 */
3040
3041static void reset_intr(void)
3042{
Joe Perchesb46df352010-03-10 15:20:46 -08003043 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044}
3045
3046static struct cont_t reset_cont = {
3047 .interrupt = reset_intr,
3048 .redo = success_and_wakeup,
3049 .error = generic_failure,
3050 .done = generic_done
3051};
3052
3053static int user_reset_fdc(int drive, int arg, int interruptible)
3054{
3055 int ret;
3056
Joe Perches52a0d612010-03-10 15:20:53 -08003057 if (lock_fdc(drive, interruptible))
3058 return -EINTR;
3059
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 if (arg == FD_RESET_ALWAYS)
3061 FDCS->reset = 1;
3062 if (FDCS->reset) {
3063 cont = &reset_cont;
3064 WAIT(reset_fdc);
3065 }
3066 process_fd_request();
Joe Perches52a0d612010-03-10 15:20:53 -08003067 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068}
3069
3070/*
3071 * Misc Ioctl's and support
3072 * ========================
3073 */
3074static inline int fd_copyout(void __user *param, const void *address,
3075 unsigned long size)
3076{
3077 return copy_to_user(param, address, size) ? -EFAULT : 0;
3078}
3079
Joe Perches48c8cee2010-03-10 15:20:45 -08003080static inline int fd_copyin(void __user *param, void *address,
3081 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082{
3083 return copy_from_user(address, param, size) ? -EFAULT : 0;
3084}
3085
Joe Perches48c8cee2010-03-10 15:20:45 -08003086#define _COPYOUT(x) (copy_to_user((void __user *)param, &(x), sizeof(x)) \
3087 ? -EFAULT : 0)
3088#define _COPYIN(x) (copy_from_user(&(x), (void __user *)param, sizeof(x)) \
3089 ? -EFAULT : 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090
Joe Perches48c8cee2010-03-10 15:20:45 -08003091#define COPYOUT(x) ECALL(_COPYOUT(x))
3092#define COPYIN(x) ECALL(_COPYIN(x))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093
3094static inline const char *drive_name(int type, int drive)
3095{
3096 struct floppy_struct *floppy;
3097
3098 if (type)
3099 floppy = floppy_type + type;
3100 else {
3101 if (UDP->native_format)
3102 floppy = floppy_type + UDP->native_format;
3103 else
3104 return "(null)";
3105 }
3106 if (floppy->name)
3107 return floppy->name;
3108 else
3109 return "(null)";
3110}
3111
3112/* raw commands */
3113static void raw_cmd_done(int flag)
3114{
3115 int i;
3116
3117 if (!flag) {
3118 raw_cmd->flags |= FD_RAW_FAILURE;
3119 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3120 } else {
3121 raw_cmd->reply_count = inr;
3122 if (raw_cmd->reply_count > MAX_REPLIES)
3123 raw_cmd->reply_count = 0;
3124 for (i = 0; i < raw_cmd->reply_count; i++)
3125 raw_cmd->reply[i] = reply_buffer[i];
3126
3127 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3128 unsigned long flags;
3129 flags = claim_dma_lock();
3130 raw_cmd->length = fd_get_dma_residue();
3131 release_dma_lock(flags);
3132 }
3133
3134 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3135 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3136 raw_cmd->flags |= FD_RAW_FAILURE;
3137
3138 if (disk_change(current_drive))
3139 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3140 else
3141 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3142 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3143 motor_off_callback(current_drive);
3144
3145 if (raw_cmd->next &&
3146 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3147 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3148 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3149 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3150 raw_cmd = raw_cmd->next;
3151 return;
3152 }
3153 }
3154 generic_done(flag);
3155}
3156
3157static struct cont_t raw_cmd_cont = {
3158 .interrupt = success_and_wakeup,
3159 .redo = floppy_start,
3160 .error = generic_failure,
3161 .done = raw_cmd_done
3162};
3163
3164static inline int raw_cmd_copyout(int cmd, char __user *param,
3165 struct floppy_raw_cmd *ptr)
3166{
3167 int ret;
3168
3169 while (ptr) {
3170 COPYOUT(*ptr);
3171 param += sizeof(struct floppy_raw_cmd);
3172 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003173 if (ptr->length >= 0 &&
3174 ptr->length <= ptr->buffer_length) {
3175 long length = ptr->buffer_length - ptr->length;
3176 ECALL(fd_copyout(ptr->data, ptr->kernel_data,
3177 length));
3178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 }
3180 ptr = ptr->next;
3181 }
3182 return 0;
3183}
3184
3185static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3186{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003187 struct floppy_raw_cmd *next;
3188 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189
3190 this = *ptr;
3191 *ptr = NULL;
3192 while (this) {
3193 if (this->buffer_length) {
3194 fd_dma_mem_free((unsigned long)this->kernel_data,
3195 this->buffer_length);
3196 this->buffer_length = 0;
3197 }
3198 next = this->next;
3199 kfree(this);
3200 this = next;
3201 }
3202}
3203
3204static inline int raw_cmd_copyin(int cmd, char __user *param,
3205 struct floppy_raw_cmd **rcmd)
3206{
3207 struct floppy_raw_cmd *ptr;
3208 int ret;
3209 int i;
3210
3211 *rcmd = NULL;
3212 while (1) {
3213 ptr = (struct floppy_raw_cmd *)
3214 kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3215 if (!ptr)
3216 return -ENOMEM;
3217 *rcmd = ptr;
3218 COPYIN(*ptr);
3219 ptr->next = NULL;
3220 ptr->buffer_length = 0;
3221 param += sizeof(struct floppy_raw_cmd);
3222 if (ptr->cmd_count > 33)
3223 /* the command may now also take up the space
3224 * initially intended for the reply & the
3225 * reply count. Needed for long 82078 commands
3226 * such as RESTORE, which takes ... 17 command
3227 * bytes. Murphy's law #137: When you reserve
3228 * 16 bytes for a structure, you'll one day
3229 * discover that you really need 17...
3230 */
3231 return -EINVAL;
3232
3233 for (i = 0; i < 16; i++)
3234 ptr->reply[i] = 0;
3235 ptr->resultcode = 0;
3236 ptr->kernel_data = NULL;
3237
3238 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3239 if (ptr->length <= 0)
3240 return -EINVAL;
3241 ptr->kernel_data =
3242 (char *)fd_dma_mem_alloc(ptr->length);
3243 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3244 if (!ptr->kernel_data)
3245 return -ENOMEM;
3246 ptr->buffer_length = ptr->length;
3247 }
3248 if (ptr->flags & FD_RAW_WRITE)
3249 ECALL(fd_copyin(ptr->data, ptr->kernel_data,
3250 ptr->length));
3251 rcmd = &(ptr->next);
3252 if (!(ptr->flags & FD_RAW_MORE))
3253 return 0;
3254 ptr->rate &= 0x43;
3255 }
3256}
3257
3258static int raw_cmd_ioctl(int cmd, void __user *param)
3259{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003261 int drive;
3262 int ret2;
3263 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264
3265 if (FDCS->rawcmd <= 1)
3266 FDCS->rawcmd = 1;
3267 for (drive = 0; drive < N_DRIVE; drive++) {
3268 if (FDC(drive) != fdc)
3269 continue;
3270 if (drive == current_drive) {
3271 if (UDRS->fd_ref > 1) {
3272 FDCS->rawcmd = 2;
3273 break;
3274 }
3275 } else if (UDRS->fd_ref) {
3276 FDCS->rawcmd = 2;
3277 break;
3278 }
3279 }
3280
3281 if (FDCS->reset)
3282 return -EIO;
3283
3284 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3285 if (ret) {
3286 raw_cmd_free(&my_raw_cmd);
3287 return ret;
3288 }
3289
3290 raw_cmd = my_raw_cmd;
3291 cont = &raw_cmd_cont;
3292 ret = wait_til_done(floppy_start, 1);
3293#ifdef DCL_DEBUG
Joe Perchesa81ee542010-03-10 15:20:46 -08003294 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 DPRINT("calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296#endif
3297
3298 if (ret != -EINTR && FDCS->reset)
3299 ret = -EIO;
3300
3301 DRS->track = NO_TRACK;
3302
3303 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3304 if (!ret)
3305 ret = ret2;
3306 raw_cmd_free(&my_raw_cmd);
3307 return ret;
3308}
3309
3310static int invalidate_drive(struct block_device *bdev)
3311{
3312 /* invalidate the buffer track to force a reread */
3313 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3314 process_fd_request();
3315 check_disk_change(bdev);
3316 return 0;
3317}
3318
3319static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
3320 int drive, int type, struct block_device *bdev)
3321{
3322 int cnt;
3323
3324 /* sanity checking for parameters. */
3325 if (g->sect <= 0 ||
3326 g->head <= 0 ||
3327 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3328 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003329 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330 return -EINVAL;
3331 if (type) {
3332 if (!capable(CAP_SYS_ADMIN))
3333 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003334 mutex_lock(&open_lock);
Jiri Slaby8516a502009-06-30 11:41:44 -07003335 if (lock_fdc(drive, 1)) {
3336 mutex_unlock(&open_lock);
3337 return -EINTR;
3338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 floppy_type[type] = *g;
3340 floppy_type[type].name = "user format";
3341 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3342 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3343 floppy_type[type].size + 1;
3344 process_fd_request();
3345 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3346 struct block_device *bdev = opened_bdev[cnt];
3347 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3348 continue;
Christoph Hellwig2ef41632005-05-05 16:15:59 -07003349 __invalidate_device(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003351 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 } else {
3353 int oldStretch;
Joe Perches52a0d612010-03-10 15:20:53 -08003354
3355 if (lock_fdc(drive, 1))
3356 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357 if (cmd != FDDEFPRM)
3358 /* notice a disk change immediately, else
3359 * we lose our settings immediately*/
3360 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3361 oldStretch = g->stretch;
3362 user_params[drive] = *g;
3363 if (buffer_drive == drive)
3364 SUPBOUND(buffer_max, user_params[drive].sect);
3365 current_type[drive] = &user_params[drive];
3366 floppy_sizes[drive] = user_params[drive].size;
3367 if (cmd == FDDEFPRM)
3368 DRS->keep_data = -1;
3369 else
3370 DRS->keep_data = 1;
3371 /* invalidation. Invalidate only when needed, i.e.
3372 * when there are already sectors in the buffer cache
3373 * whose number will change. This is useful, because
3374 * mtools often changes the geometry of the disk after
3375 * looking at the boot block */
3376 if (DRS->maxblock > user_params[drive].sect ||
3377 DRS->maxtrack ||
3378 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003379 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 invalidate_drive(bdev);
3381 else
3382 process_fd_request();
3383 }
3384 return 0;
3385}
3386
3387/* handle obsolete ioctl's */
3388static int ioctl_table[] = {
3389 FDCLRPRM,
3390 FDSETPRM,
3391 FDDEFPRM,
3392 FDGETPRM,
3393 FDMSGON,
3394 FDMSGOFF,
3395 FDFMTBEG,
3396 FDFMTTRK,
3397 FDFMTEND,
3398 FDSETEMSGTRESH,
3399 FDFLUSH,
3400 FDSETMAXERRS,
3401 FDGETMAXERRS,
3402 FDGETDRVTYP,
3403 FDSETDRVPRM,
3404 FDGETDRVPRM,
3405 FDGETDRVSTAT,
3406 FDPOLLDRVSTAT,
3407 FDRESET,
3408 FDGETFDCSTAT,
3409 FDWERRORCLR,
3410 FDWERRORGET,
3411 FDRAWCMD,
3412 FDEJECT,
3413 FDTWADDLE
3414};
3415
3416static inline int normalize_ioctl(int *cmd, int *size)
3417{
3418 int i;
3419
3420 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3421 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3422 *size = _IOC_SIZE(*cmd);
3423 *cmd = ioctl_table[i];
3424 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003425 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 return -EFAULT;
3427 }
3428 return 0;
3429 }
3430 }
3431 return -EINVAL;
3432}
3433
3434static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3435{
3436 if (type)
3437 *g = &floppy_type[type];
3438 else {
Joe Perches52a0d612010-03-10 15:20:53 -08003439 if (lock_fdc(drive, 0))
3440 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441 CALL(poll_drive(0, 0));
3442 process_fd_request();
3443 *g = current_type[drive];
3444 }
3445 if (!*g)
3446 return -ENODEV;
3447 return 0;
3448}
3449
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003450static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3451{
3452 int drive = (long)bdev->bd_disk->private_data;
3453 int type = ITYPE(drive_state[drive].fd_device);
3454 struct floppy_struct *g;
3455 int ret;
3456
3457 ret = get_floppy_geometry(drive, type, &g);
3458 if (ret)
3459 return ret;
3460
3461 geo->heads = g->head;
3462 geo->sectors = g->sect;
3463 geo->cylinders = g->track;
3464 return 0;
3465}
3466
Al Viroa4af9b42008-03-02 09:27:55 -05003467static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 unsigned long param)
3469{
Al Viroa4af9b42008-03-02 09:27:55 -05003470#define FD_IOCTL_ALLOWED (mode & (FMODE_WRITE|FMODE_WRITE_IOCTL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471
Al Viroa4af9b42008-03-02 09:27:55 -05003472 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003473 int type = ITYPE(UDRS->fd_device);
3474 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 int ret;
3476 int size;
3477 union inparam {
3478 struct floppy_struct g; /* geometry */
3479 struct format_descr f;
3480 struct floppy_max_errors max_errors;
3481 struct floppy_drive_params dp;
3482 } inparam; /* parameters coming from user space */
3483 const char *outparam; /* parameters passed back to user space */
3484
3485 /* convert compatibility eject ioctls into floppy eject ioctl.
3486 * We do this in order to provide a means to eject floppy disks before
3487 * installing the new fdutils package */
3488 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003489 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 DPRINT("obsolete eject ioctl\n");
3491 DPRINT("please use floppycontrol --eject\n");
3492 cmd = FDEJECT;
3493 }
3494
Joe Perchesa81ee542010-03-10 15:20:46 -08003495 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 return -EINVAL;
3497
Joe Perchesa81ee542010-03-10 15:20:46 -08003498 /* convert the old style command into a new style command */
3499 ECALL(normalize_ioctl(&cmd, &size));
3500
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501 /* permission checks */
3502 if (((cmd & 0x40) && !FD_IOCTL_ALLOWED) ||
3503 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3504 return -EPERM;
3505
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003506 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3507 return -EINVAL;
3508
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509 /* copyin */
Joe Perchesb87c9e02010-03-10 15:20:50 -08003510 memset(&inparam, 0, sizeof(inparam));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 if (_IOC_DIR(cmd) & _IOC_WRITE)
Joe Perchesda273652010-03-10 15:20:52 -08003512 ECALL(fd_copyin((void __user *)param, &inparam, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513
Joe Perchesda273652010-03-10 15:20:52 -08003514 switch (cmd) {
3515 case FDEJECT:
3516 if (UDRS->fd_ref != 1)
3517 /* somebody else has this drive open */
3518 return -EBUSY;
Joe Perches52a0d612010-03-10 15:20:53 -08003519 if (lock_fdc(drive, 1))
3520 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521
Joe Perchesda273652010-03-10 15:20:52 -08003522 /* do the actual eject. Fails on
3523 * non-Sparc architectures */
3524 ret = fd_eject(UNIT(drive));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525
Joe Perchesda273652010-03-10 15:20:52 -08003526 USETF(FD_DISK_CHANGED);
3527 USETF(FD_VERIFY);
3528 process_fd_request();
3529 return ret;
3530 case FDCLRPRM:
Joe Perches52a0d612010-03-10 15:20:53 -08003531 if (lock_fdc(drive, 1))
3532 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003533 current_type[drive] = NULL;
3534 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3535 UDRS->keep_data = 0;
3536 return invalidate_drive(bdev);
3537 case FDSETPRM:
3538 case FDDEFPRM:
3539 return set_geometry(cmd, &inparam.g, drive, type, bdev);
3540 case FDGETPRM:
3541 ECALL(get_floppy_geometry(drive, type,
3542 (struct floppy_struct **)
3543 &outparam));
3544 break;
3545 case FDMSGON:
3546 UDP->flags |= FTD_MSG;
3547 return 0;
3548 case FDMSGOFF:
3549 UDP->flags &= ~FTD_MSG;
3550 return 0;
3551 case FDFMTBEG:
Joe Perches52a0d612010-03-10 15:20:53 -08003552 if (lock_fdc(drive, 1))
3553 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003554 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3555 ret = UDRS->flags;
3556 process_fd_request();
3557 if (ret & FD_VERIFY)
3558 return -ENODEV;
3559 if (!(ret & FD_DISK_WRITABLE))
3560 return -EROFS;
3561 return 0;
3562 case FDFMTTRK:
3563 if (UDRS->fd_ref != 1)
3564 return -EBUSY;
3565 return do_format(drive, &inparam.f);
3566 case FDFMTEND:
3567 case FDFLUSH:
Joe Perches52a0d612010-03-10 15:20:53 -08003568 if (lock_fdc(drive, 1))
3569 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003570 return invalidate_drive(bdev);
3571 case FDSETEMSGTRESH:
3572 UDP->max_errors.reporting = (unsigned short)(param & 0x0f);
3573 return 0;
3574 case FDGETMAXERRS:
3575 outparam = (const char *)&UDP->max_errors;
3576 break;
3577 case FDSETMAXERRS:
3578 UDP->max_errors = inparam.max_errors;
3579 break;
3580 case FDGETDRVTYP:
3581 outparam = drive_name(type, drive);
3582 SUPBOUND(size, strlen(outparam) + 1);
3583 break;
3584 case FDSETDRVPRM:
3585 *UDP = inparam.dp;
3586 break;
3587 case FDGETDRVPRM:
3588 outparam = (const char *)UDP;
3589 break;
3590 case FDPOLLDRVSTAT:
Joe Perches52a0d612010-03-10 15:20:53 -08003591 if (lock_fdc(drive, 1))
3592 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003593 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3594 process_fd_request();
3595 /* fall through */
3596 case FDGETDRVSTAT:
3597 outparam = (const char *)UDRS;
3598 break;
3599 case FDRESET:
3600 return user_reset_fdc(drive, (int)param, 1);
3601 case FDGETFDCSTAT:
3602 outparam = (const char *)UFDCS;
3603 break;
3604 case FDWERRORCLR:
3605 memset(UDRWE, 0, sizeof(*UDRWE));
3606 return 0;
3607 case FDWERRORGET:
3608 outparam = (const char *)UDRWE;
3609 break;
3610 case FDRAWCMD:
3611 if (type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612 return -EINVAL;
Joe Perches52a0d612010-03-10 15:20:53 -08003613 if (lock_fdc(drive, 1))
3614 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003615 set_floppy(drive);
3616 CALL(i = raw_cmd_ioctl(cmd, (void __user *)param));
3617 process_fd_request();
3618 return i;
3619 case FDTWADDLE:
Joe Perches52a0d612010-03-10 15:20:53 -08003620 if (lock_fdc(drive, 1))
3621 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003622 twaddle();
3623 process_fd_request();
3624 return 0;
3625 default:
3626 return -EINVAL;
3627 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628
3629 if (_IOC_DIR(cmd) & _IOC_READ)
3630 return fd_copyout((void __user *)param, outparam, size);
Joe Perchesda273652010-03-10 15:20:52 -08003631
3632 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633}
3634
3635static void __init config_types(void)
3636{
Joe Perchesb46df352010-03-10 15:20:46 -08003637 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 int drive;
3639
3640 /* read drive info out of physical CMOS */
3641 drive = 0;
3642 if (!UDP->cmos)
3643 UDP->cmos = FLOPPY0_TYPE;
3644 drive = 1;
3645 if (!UDP->cmos && FLOPPY1_TYPE)
3646 UDP->cmos = FLOPPY1_TYPE;
3647
Jesper Juhl06f748c2007-10-16 23:30:57 -07003648 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649
3650 for (drive = 0; drive < N_DRIVE; drive++) {
3651 unsigned int type = UDP->cmos;
3652 struct floppy_drive_params *params;
3653 const char *name = NULL;
3654 static char temparea[32];
3655
Tobias Klauser945f3902006-01-08 01:05:11 -08003656 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 params = &default_drive_params[type].params;
3658 if (type) {
3659 name = default_drive_params[type].name;
3660 allowed_drive_mask |= 1 << drive;
3661 } else
3662 allowed_drive_mask &= ~(1 << drive);
3663 } else {
3664 params = &default_drive_params[0].params;
3665 sprintf(temparea, "unknown type %d (usb?)", type);
3666 name = temparea;
3667 }
3668 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003669 const char *prepend;
3670 if (!has_drive) {
3671 prepend = "";
3672 has_drive = true;
3673 pr_info("Floppy drive(s):");
3674 } else {
3675 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 }
Joe Perchesb46df352010-03-10 15:20:46 -08003677
3678 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679 }
3680 *UDP = *params;
3681 }
Joe Perchesb46df352010-03-10 15:20:46 -08003682
3683 if (has_drive)
3684 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685}
3686
Al Viroa4af9b42008-03-02 09:27:55 -05003687static int floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688{
Al Viroa4af9b42008-03-02 09:27:55 -05003689 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003691 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 if (UDRS->fd_ref < 0)
3693 UDRS->fd_ref = 0;
3694 else if (!UDRS->fd_ref--) {
3695 DPRINT("floppy_release with fd_ref == 0");
3696 UDRS->fd_ref = 0;
3697 }
3698 if (!UDRS->fd_ref)
3699 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003700 mutex_unlock(&open_lock);
Ingo Molnar3e541a42006-07-03 00:24:23 -07003701
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 return 0;
3703}
3704
3705/*
3706 * floppy_open check for aliasing (/dev/fd0 can be the same as
3707 * /dev/PS0 etc), and disallows simultaneous access to the same
3708 * drive with different device numbers.
3709 */
Al Viroa4af9b42008-03-02 09:27:55 -05003710static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711{
Al Viroa4af9b42008-03-02 09:27:55 -05003712 int drive = (long)bdev->bd_disk->private_data;
3713 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714 int try;
3715 int res = -EBUSY;
3716 char *tmp;
3717
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003718 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003720 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721 goto out2;
3722
3723 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
3724 USETF(FD_DISK_CHANGED);
3725 USETF(FD_VERIFY);
3726 }
3727
Al Viroa4af9b42008-03-02 09:27:55 -05003728 if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729 goto out2;
3730
Al Viroa4af9b42008-03-02 09:27:55 -05003731 if (mode & FMODE_EXCL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732 UDRS->fd_ref = -1;
3733 else
3734 UDRS->fd_ref++;
3735
Al Viroa4af9b42008-03-02 09:27:55 -05003736 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003737
3738 res = -ENXIO;
3739
3740 if (!floppy_track_buffer) {
3741 /* if opening an ED drive, reserve a big buffer,
3742 * else reserve a small one */
3743 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3744 try = 64; /* Only 48 actually useful */
3745 else
3746 try = 32; /* Only 24 actually useful */
3747
3748 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3749 if (!tmp && !floppy_track_buffer) {
3750 try >>= 1; /* buffer only one side */
3751 INFBOUND(try, 16);
3752 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3753 }
Joe Perchesa81ee542010-03-10 15:20:46 -08003754 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756 if (!tmp && !floppy_track_buffer) {
3757 DPRINT("Unable to allocate DMA memory\n");
3758 goto out;
3759 }
3760 if (floppy_track_buffer) {
3761 if (tmp)
3762 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3763 } else {
3764 buffer_min = buffer_max = -1;
3765 floppy_track_buffer = tmp;
3766 max_buffer_sectors = try;
3767 }
3768 }
3769
Al Viroa4af9b42008-03-02 09:27:55 -05003770 new_dev = MINOR(bdev->bd_dev);
3771 UDRS->fd_device = new_dev;
3772 set_capacity(disks[drive], floppy_sizes[new_dev]);
3773 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774 if (buffer_drive == drive)
3775 buffer_track = -1;
3776 }
3777
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778 if (UFDCS->rawcmd == 1)
3779 UFDCS->rawcmd = 2;
3780
Al Viroa4af9b42008-03-02 09:27:55 -05003781 if (!(mode & FMODE_NDELAY)) {
3782 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783 UDRS->last_checked = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003784 check_disk_change(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 if (UTESTF(FD_DISK_CHANGED))
3786 goto out;
3787 }
3788 res = -EROFS;
Al Viroa4af9b42008-03-02 09:27:55 -05003789 if ((mode & FMODE_WRITE) && !(UTESTF(FD_DISK_WRITABLE)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 goto out;
3791 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003792 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793 return 0;
3794out:
3795 if (UDRS->fd_ref < 0)
3796 UDRS->fd_ref = 0;
3797 else
3798 UDRS->fd_ref--;
3799 if (!UDRS->fd_ref)
3800 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003802 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803 return res;
3804}
3805
3806/*
3807 * Check if the disk has been changed or if a change has been faked.
3808 */
3809static int check_floppy_change(struct gendisk *disk)
3810{
3811 int drive = (long)disk->private_data;
3812
3813 if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY))
3814 return 1;
3815
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003816 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 lock_fdc(drive, 0);
3818 poll_drive(0, 0);
3819 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820 }
3821
3822 if (UTESTF(FD_DISK_CHANGED) ||
3823 UTESTF(FD_VERIFY) ||
3824 test_bit(drive, &fake_change) ||
3825 (!ITYPE(UDRS->fd_device) && !current_type[drive]))
3826 return 1;
3827 return 0;
3828}
3829
3830/*
3831 * This implements "read block 0" for floppy_revalidate().
3832 * Needed for format autodetection, checking whether there is
3833 * a disk in the drive, and whether that disk is writable.
3834 */
3835
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003836static void floppy_rb0_complete(struct bio *bio, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 complete((struct completion *)bio->bi_private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839}
3840
3841static int __floppy_read_block_0(struct block_device *bdev)
3842{
3843 struct bio bio;
3844 struct bio_vec bio_vec;
3845 struct completion complete;
3846 struct page *page;
3847 size_t size;
3848
3849 page = alloc_page(GFP_NOIO);
3850 if (!page) {
3851 process_fd_request();
3852 return -ENOMEM;
3853 }
3854
3855 size = bdev->bd_block_size;
3856 if (!size)
3857 size = 1024;
3858
3859 bio_init(&bio);
3860 bio.bi_io_vec = &bio_vec;
3861 bio_vec.bv_page = page;
3862 bio_vec.bv_len = size;
3863 bio_vec.bv_offset = 0;
3864 bio.bi_vcnt = 1;
3865 bio.bi_idx = 0;
3866 bio.bi_size = size;
3867 bio.bi_bdev = bdev;
3868 bio.bi_sector = 0;
3869 init_completion(&complete);
3870 bio.bi_private = &complete;
3871 bio.bi_end_io = floppy_rb0_complete;
3872
3873 submit_bio(READ, &bio);
3874 generic_unplug_device(bdev_get_queue(bdev));
3875 process_fd_request();
3876 wait_for_completion(&complete);
3877
3878 __free_page(page);
3879
3880 return 0;
3881}
3882
3883/* revalidate the floppy disk, i.e. trigger format autodetection by reading
3884 * the bootblock (block 0). "Autodetection" is also needed to check whether
3885 * there is a disk in the drive at all... Thus we also do it for fixed
3886 * geometry formats */
3887static int floppy_revalidate(struct gendisk *disk)
3888{
3889 int drive = (long)disk->private_data;
3890#define NO_GEOM (!current_type[drive] && !ITYPE(UDRS->fd_device))
3891 int cf;
3892 int res = 0;
3893
3894 if (UTESTF(FD_DISK_CHANGED) ||
3895 UTESTF(FD_VERIFY) || test_bit(drive, &fake_change) || NO_GEOM) {
3896 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08003897 pr_info("VFS: revalidate called on non-open device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003898 return -EFAULT;
3899 }
3900 lock_fdc(drive, 0);
3901 cf = UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY);
3902 if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)) {
3903 process_fd_request(); /*already done by another thread */
3904 return 0;
3905 }
3906 UDRS->maxblock = 0;
3907 UDRS->maxtrack = 0;
3908 if (buffer_drive == drive)
3909 buffer_track = -1;
3910 clear_bit(drive, &fake_change);
3911 UCLEARF(FD_DISK_CHANGED);
3912 if (cf)
3913 UDRS->generation++;
3914 if (NO_GEOM) {
3915 /* auto-sensing */
3916 res = __floppy_read_block_0(opened_bdev[drive]);
3917 } else {
3918 if (cf)
3919 poll_drive(0, FD_RAW_NEED_DISK);
3920 process_fd_request();
3921 }
3922 }
3923 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
3924 return res;
3925}
3926
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07003927static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07003928 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05003929 .open = floppy_open,
3930 .release = floppy_release,
3931 .locked_ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003932 .getgeo = fd_getgeo,
3933 .media_changed = check_floppy_change,
3934 .revalidate_disk = floppy_revalidate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937/*
3938 * Floppy Driver initialization
3939 * =============================
3940 */
3941
3942/* Determine the floppy disk controller type */
3943/* This routine was written by David C. Niemi */
3944static char __init get_fdc_version(void)
3945{
3946 int r;
3947
3948 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
3949 if (FDCS->reset)
3950 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003951 r = result();
3952 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 return FDC_NONE; /* No FDC present ??? */
3954 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003955 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3957 }
3958 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003959 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3960 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 return FDC_UNKNOWN;
3962 }
3963
3964 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003965 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3967 }
3968
3969 output_byte(FD_PERPENDICULAR);
3970 if (need_more_output() == MORE_OUTPUT) {
3971 output_byte(0);
3972 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003973 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974 return FDC_82072A; /* 82072A as found on Sparcs. */
3975 }
3976
3977 output_byte(FD_UNLOCK);
3978 r = result();
3979 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003980 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003981 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982 * LOCK/UNLOCK */
3983 }
3984 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003985 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3986 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 return FDC_UNKNOWN;
3988 }
3989 output_byte(FD_PARTID);
3990 r = result();
3991 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003992 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3993 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 return FDC_UNKNOWN;
3995 }
3996 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003997 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 return FDC_82077; /* Revised 82077AA passes all the tests */
3999 }
4000 switch (reply_buffer[0] >> 5) {
4001 case 0x0:
4002 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08004003 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 return FDC_82078;
4005 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08004006 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 return FDC_82078;
4008 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08004009 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 return FDC_S82078B;
4011 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08004012 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 return FDC_87306;
4014 default:
Joe Perchesb46df352010-03-10 15:20:46 -08004015 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
4016 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017 return FDC_82078_UNKN;
4018 }
4019} /* get_fdc_version */
4020
4021/* lilo configuration */
4022
4023static void __init floppy_set_flags(int *ints, int param, int param2)
4024{
4025 int i;
4026
4027 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4028 if (param)
4029 default_drive_params[i].params.flags |= param2;
4030 else
4031 default_drive_params[i].params.flags &= ~param2;
4032 }
4033 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
4034}
4035
4036static void __init daring(int *ints, int param, int param2)
4037{
4038 int i;
4039
4040 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4041 if (param) {
4042 default_drive_params[i].params.select_delay = 0;
4043 default_drive_params[i].params.flags |=
4044 FD_SILENT_DCL_CLEAR;
4045 } else {
4046 default_drive_params[i].params.select_delay =
4047 2 * HZ / 100;
4048 default_drive_params[i].params.flags &=
4049 ~FD_SILENT_DCL_CLEAR;
4050 }
4051 }
4052 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
4053}
4054
4055static void __init set_cmos(int *ints, int dummy, int dummy2)
4056{
4057 int current_drive = 0;
4058
4059 if (ints[0] != 2) {
4060 DPRINT("wrong number of parameters for CMOS\n");
4061 return;
4062 }
4063 current_drive = ints[1];
4064 if (current_drive < 0 || current_drive >= 8) {
4065 DPRINT("bad drive for set_cmos\n");
4066 return;
4067 }
4068#if N_FDC > 1
4069 if (current_drive >= 4 && !FDC2)
4070 FDC2 = 0x370;
4071#endif
4072 DP->cmos = ints[2];
4073 DPRINT("setting CMOS code to %d\n", ints[2]);
4074}
4075
4076static struct param_table {
4077 const char *name;
4078 void (*fn) (int *ints, int param, int param2);
4079 int *var;
4080 int def_param;
4081 int param2;
4082} config_params[] __initdata = {
4083 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4084 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4085 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4086 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4087 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4088 {"daring", daring, NULL, 1, 0},
4089#if N_FDC > 1
4090 {"two_fdc", NULL, &FDC2, 0x370, 0},
4091 {"one_fdc", NULL, &FDC2, 0, 0},
4092#endif
4093 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4094 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4095 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4096 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4097 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4098 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4099 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4100 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4101 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4102 {"nofifo", NULL, &no_fifo, 0x20, 0},
4103 {"usefifo", NULL, &no_fifo, 0, 0},
4104 {"cmos", set_cmos, NULL, 0, 0},
4105 {"slow", NULL, &slow_floppy, 1, 0},
4106 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4107 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4108 {"L40SX", NULL, &print_unex, 0, 0}
4109
4110 EXTRA_FLOPPY_PARAMS
4111};
4112
4113static int __init floppy_setup(char *str)
4114{
4115 int i;
4116 int param;
4117 int ints[11];
4118
4119 str = get_options(str, ARRAY_SIZE(ints), ints);
4120 if (str) {
4121 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4122 if (strcmp(str, config_params[i].name) == 0) {
4123 if (ints[0])
4124 param = ints[1];
4125 else
4126 param = config_params[i].def_param;
4127 if (config_params[i].fn)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004128 config_params[i].fn(ints, param,
4129 config_params[i].
4130 param2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131 if (config_params[i].var) {
4132 DPRINT("%s=%d\n", str, param);
4133 *config_params[i].var = param;
4134 }
4135 return 1;
4136 }
4137 }
4138 }
4139 if (str) {
4140 DPRINT("unknown floppy option [%s]\n", str);
4141
4142 DPRINT("allowed options are:");
4143 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004144 pr_cont(" %s", config_params[i].name);
4145 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146 } else
4147 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004148 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149 return 0;
4150}
4151
4152static int have_no_fdc = -ENODEV;
4153
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004154static ssize_t floppy_cmos_show(struct device *dev,
4155 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004156{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004157 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004158 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004159
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004160 drive = p->id;
4161 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004162}
Joe Perches48c8cee2010-03-10 15:20:45 -08004163
4164DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004165
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166static void floppy_device_release(struct device *dev)
4167{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168}
4169
Frans Popc90cd332009-07-25 22:24:54 +02004170static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004171{
4172 int fdc;
4173
4174 for (fdc = 0; fdc < N_FDC; fdc++)
4175 if (FDCS->address != -1)
4176 user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
4177
4178 return 0;
4179}
4180
Alexey Dobriyan47145212009-12-14 18:00:08 -08004181static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004182 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004183 .restore = floppy_resume,
4184};
4185
4186static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004187 .driver = {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004188 .name = "floppy",
4189 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004190 },
4191};
4192
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004193static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194
4195static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4196{
4197 int drive = (*part & 3) | ((*part & 0x80) >> 5);
4198 if (drive >= N_DRIVE ||
4199 !(allowed_drive_mask & (1 << drive)) ||
4200 fdc_state[FDC(drive)].version == FDC_NONE)
4201 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004202 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203 return NULL;
4204 *part = 0;
4205 return get_disk(disks[drive]);
4206}
4207
4208static int __init floppy_init(void)
4209{
4210 int i, unit, drive;
4211 int err, dr;
4212
Kumar Gala68e1ee62008-09-22 14:41:31 -07004213#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004214 if (check_legacy_ioport(FDC1))
4215 return -ENODEV;
4216#endif
4217
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218 raw_cmd = NULL;
4219
4220 for (dr = 0; dr < N_DRIVE; dr++) {
4221 disks[dr] = alloc_disk(1);
4222 if (!disks[dr]) {
4223 err = -ENOMEM;
4224 goto out_put_disk;
4225 }
4226
4227 disks[dr]->major = FLOPPY_MAJOR;
4228 disks[dr]->first_minor = TOMINOR(dr);
4229 disks[dr]->fops = &floppy_fops;
4230 sprintf(disks[dr]->disk_name, "fd%d", dr);
4231
4232 init_timer(&motor_off_timer[dr]);
4233 motor_off_timer[dr].data = dr;
4234 motor_off_timer[dr].function = motor_off_callback;
4235 }
4236
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237 err = register_blkdev(FLOPPY_MAJOR, "fd");
4238 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004239 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004241 err = platform_driver_register(&floppy_driver);
4242 if (err)
4243 goto out_unreg_blkdev;
4244
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
4246 if (!floppy_queue) {
4247 err = -ENOMEM;
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004248 goto out_unreg_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249 }
Martin K. Petersen086fa5f2010-02-26 00:20:38 -05004250 blk_queue_max_hw_sectors(floppy_queue, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251
4252 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4253 floppy_find, NULL, NULL);
4254
4255 for (i = 0; i < 256; i++)
4256 if (ITYPE(i))
4257 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4258 else
4259 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4260
4261 reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
4262 config_types();
4263
4264 for (i = 0; i < N_FDC; i++) {
4265 fdc = i;
Joe Perchesb87c9e02010-03-10 15:20:50 -08004266 memset(FDCS, 0, sizeof(*FDCS));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267 FDCS->dtr = -1;
4268 FDCS->dor = 0x4;
4269#if defined(__sparc__) || defined(__mc68000__)
Joe Perches96534f12010-03-10 15:20:51 -08004270 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271#ifdef __mc68000__
4272 if (MACH_IS_SUN3X)
4273#endif
4274 FDCS->version = FDC_82072A;
4275#endif
4276 }
4277
4278 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279 fdc_state[0].address = FDC1;
4280 if (fdc_state[0].address == -1) {
4281 del_timer(&fd_timeout);
4282 err = -ENODEV;
4283 goto out_unreg_region;
4284 }
4285#if N_FDC > 1
4286 fdc_state[1].address = FDC2;
4287#endif
4288
4289 fdc = 0; /* reset fdc in case of unexpected interrupt */
4290 err = floppy_grab_irq_and_dma();
4291 if (err) {
4292 del_timer(&fd_timeout);
4293 err = -EBUSY;
4294 goto out_unreg_region;
4295 }
4296
4297 /* initialise drive state */
4298 for (drive = 0; drive < N_DRIVE; drive++) {
Joe Perchesb87c9e02010-03-10 15:20:50 -08004299 memset(UDRS, 0, sizeof(*UDRS));
4300 memset(UDRWE, 0, sizeof(*UDRWE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 USETF(FD_DISK_NEWCHANGE);
4302 USETF(FD_DISK_CHANGED);
4303 USETF(FD_VERIFY);
4304 UDRS->fd_device = -1;
4305 floppy_track_buffer = NULL;
4306 max_buffer_sectors = 0;
4307 }
4308 /*
4309 * Small 10 msec delay to let through any interrupt that
4310 * initialization might have triggered, to not
4311 * confuse detection:
4312 */
4313 msleep(10);
4314
4315 for (i = 0; i < N_FDC; i++) {
4316 fdc = i;
4317 FDCS->driver_version = FD_DRIVER_VERSION;
4318 for (unit = 0; unit < 4; unit++)
4319 FDCS->track[unit] = 0;
4320 if (FDCS->address == -1)
4321 continue;
4322 FDCS->rawcmd = 2;
4323 if (user_reset_fdc(-1, FD_RESET_ALWAYS, 0)) {
4324 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004325 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326 FDCS->address = -1;
4327 FDCS->version = FDC_NONE;
4328 continue;
4329 }
4330 /* Try to determine the floppy controller type */
4331 FDCS->version = get_fdc_version();
4332 if (FDCS->version == FDC_NONE) {
4333 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004334 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335 FDCS->address = -1;
4336 continue;
4337 }
4338 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4339 can_use_virtual_dma = 0;
4340
4341 have_no_fdc = 0;
4342 /* Not all FDCs seem to be able to handle the version command
4343 * properly, so force a reset for the standard FDC clones,
4344 * to avoid interrupt garbage.
4345 */
4346 user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
4347 }
4348 fdc = 0;
4349 del_timer(&fd_timeout);
4350 current_drive = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351 initialising = 0;
4352 if (have_no_fdc) {
4353 DPRINT("no floppy controllers found\n");
4354 err = have_no_fdc;
4355 goto out_flush_work;
4356 }
4357
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358 for (drive = 0; drive < N_DRIVE; drive++) {
4359 if (!(allowed_drive_mask & (1 << drive)))
4360 continue;
4361 if (fdc_state[FDC(drive)].version == FDC_NONE)
4362 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004363
4364 floppy_device[drive].name = floppy_device_name;
4365 floppy_device[drive].id = drive;
4366 floppy_device[drive].dev.release = floppy_device_release;
4367
4368 err = platform_device_register(&floppy_device[drive]);
4369 if (err)
4370 goto out_flush_work;
4371
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004372 err = device_create_file(&floppy_device[drive].dev,
4373 &dev_attr_cmos);
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004374 if (err)
4375 goto out_unreg_platform_dev;
4376
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 /* to be cleaned up... */
4378 disks[drive]->private_data = (void *)(long)drive;
4379 disks[drive]->queue = floppy_queue;
4380 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004381 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382 add_disk(disks[drive]);
4383 }
4384
4385 return 0;
4386
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004387out_unreg_platform_dev:
4388 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389out_flush_work:
4390 flush_scheduled_work();
4391 if (usage_count)
4392 floppy_release_irq_and_dma();
4393out_unreg_region:
4394 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4395 blk_cleanup_queue(floppy_queue);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004396out_unreg_driver:
4397 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398out_unreg_blkdev:
4399 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400out_put_disk:
4401 while (dr--) {
4402 del_timer(&motor_off_timer[dr]);
4403 put_disk(disks[dr]);
4404 }
4405 return err;
4406}
4407
4408static DEFINE_SPINLOCK(floppy_usage_lock);
4409
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004410static const struct io_region {
4411 int offset;
4412 int size;
4413} io_regions[] = {
4414 { 2, 1 },
4415 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4416 { 4, 2 },
4417 /* address + 6 is reserved, and may be taken by IDE.
4418 * Unfortunately, Adaptec doesn't know this :-(, */
4419 { 7, 1 },
4420};
4421
4422static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4423{
4424 while (p != io_regions) {
4425 p--;
4426 release_region(FDCS->address + p->offset, p->size);
4427 }
4428}
4429
4430#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4431
4432static int floppy_request_regions(int fdc)
4433{
4434 const struct io_region *p;
4435
4436 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004437 if (!request_region(FDCS->address + p->offset,
4438 p->size, "floppy")) {
4439 DPRINT("Floppy io-port 0x%04lx in use\n",
4440 FDCS->address + p->offset);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004441 floppy_release_allocated_regions(fdc, p);
4442 return -EBUSY;
4443 }
4444 }
4445 return 0;
4446}
4447
4448static void floppy_release_regions(int fdc)
4449{
4450 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4451}
4452
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453static int floppy_grab_irq_and_dma(void)
4454{
4455 unsigned long flags;
4456
4457 spin_lock_irqsave(&floppy_usage_lock, flags);
4458 if (usage_count++) {
4459 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4460 return 0;
4461 }
4462 spin_unlock_irqrestore(&floppy_usage_lock, flags);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004463
4464 /*
4465 * We might have scheduled a free_irq(), wait it to
4466 * drain first:
4467 */
4468 flush_scheduled_work();
4469
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 if (fd_request_irq()) {
4471 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4472 FLOPPY_IRQ);
4473 spin_lock_irqsave(&floppy_usage_lock, flags);
4474 usage_count--;
4475 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4476 return -1;
4477 }
4478 if (fd_request_dma()) {
4479 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4480 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004481 if (can_use_virtual_dma & 2)
4482 use_virtual_dma = can_use_virtual_dma = 1;
4483 if (!(can_use_virtual_dma & 1)) {
4484 fd_free_irq();
4485 spin_lock_irqsave(&floppy_usage_lock, flags);
4486 usage_count--;
4487 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4488 return -1;
4489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 }
4491
4492 for (fdc = 0; fdc < N_FDC; fdc++) {
4493 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004494 if (floppy_request_regions(fdc))
4495 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496 }
4497 }
4498 for (fdc = 0; fdc < N_FDC; fdc++) {
4499 if (FDCS->address != -1) {
4500 reset_fdc_info(1);
4501 fd_outb(FDCS->dor, FD_DOR);
4502 }
4503 }
4504 fdc = 0;
4505 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4506
4507 for (fdc = 0; fdc < N_FDC; fdc++)
4508 if (FDCS->address != -1)
4509 fd_outb(FDCS->dor, FD_DOR);
4510 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004511 * The driver will try and free resources and relies on us
4512 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513 */
4514 fdc = 0;
4515 irqdma_allocated = 1;
4516 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004517cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 fd_free_irq();
4519 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004520 while (--fdc >= 0)
4521 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522 spin_lock_irqsave(&floppy_usage_lock, flags);
4523 usage_count--;
4524 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4525 return -1;
4526}
4527
4528static void floppy_release_irq_and_dma(void)
4529{
4530 int old_fdc;
4531#ifdef FLOPPY_SANITY_CHECK
4532#ifndef __sparc__
4533 int drive;
4534#endif
4535#endif
4536 long tmpsize;
4537 unsigned long tmpaddr;
4538 unsigned long flags;
4539
4540 spin_lock_irqsave(&floppy_usage_lock, flags);
4541 if (--usage_count) {
4542 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4543 return;
4544 }
4545 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4546 if (irqdma_allocated) {
4547 fd_disable_dma();
4548 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004549 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550 irqdma_allocated = 0;
4551 }
4552 set_dor(0, ~0, 8);
4553#if N_FDC > 1
4554 set_dor(1, ~8, 0);
4555#endif
4556 floppy_enable_hlt();
4557
4558 if (floppy_track_buffer && max_buffer_sectors) {
4559 tmpsize = max_buffer_sectors * 1024;
4560 tmpaddr = (unsigned long)floppy_track_buffer;
4561 floppy_track_buffer = NULL;
4562 max_buffer_sectors = 0;
4563 buffer_min = buffer_max = -1;
4564 fd_dma_mem_free(tmpaddr, tmpsize);
4565 }
4566#ifdef FLOPPY_SANITY_CHECK
4567#ifndef __sparc__
4568 for (drive = 0; drive < N_FDC * 4; drive++)
4569 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004570 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571#endif
4572
4573 if (timer_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004574 pr_info("floppy timer still active:%s\n", timeout_message);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004576 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004577 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004578 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579#endif
4580 old_fdc = fdc;
4581 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004582 if (FDCS->address != -1)
4583 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584 fdc = old_fdc;
4585}
4586
4587#ifdef MODULE
4588
4589static char *floppy;
4590
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591static void __init parse_floppy_cfg_string(char *cfg)
4592{
4593 char *ptr;
4594
4595 while (*cfg) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004596 ptr = cfg;
4597 while (*cfg && *cfg != ' ' && *cfg != '\t')
4598 cfg++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 if (*cfg) {
4600 *cfg = '\0';
4601 cfg++;
4602 }
4603 if (*ptr)
4604 floppy_setup(ptr);
4605 }
4606}
4607
Jon Schindler7afea3b2008-04-29 00:59:21 -07004608static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609{
4610 if (floppy)
4611 parse_floppy_cfg_string(floppy);
4612 return floppy_init();
4613}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004614module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615
Jon Schindler7afea3b2008-04-29 00:59:21 -07004616static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617{
4618 int drive;
4619
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4621 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004622 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623
4624 for (drive = 0; drive < N_DRIVE; drive++) {
4625 del_timer_sync(&motor_off_timer[drive]);
4626
4627 if ((allowed_drive_mask & (1 << drive)) &&
4628 fdc_state[FDC(drive)].version != FDC_NONE) {
4629 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004630 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4631 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632 }
4633 put_disk(disks[drive]);
4634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635
4636 del_timer_sync(&fd_timeout);
4637 del_timer_sync(&fd_timer);
4638 blk_cleanup_queue(floppy_queue);
4639
4640 if (usage_count)
4641 floppy_release_irq_and_dma();
4642
4643 /* eject disk, if any */
4644 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645}
Joe Perches48c8cee2010-03-10 15:20:45 -08004646
Jon Schindler7afea3b2008-04-29 00:59:21 -07004647module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648
4649module_param(floppy, charp, 0);
4650module_param(FLOPPY_IRQ, int, 0);
4651module_param(FLOPPY_DMA, int, 0);
4652MODULE_AUTHOR("Alain L. Knaff");
4653MODULE_SUPPORTED_DEVICE("fd");
4654MODULE_LICENSE("GPL");
4655
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004656/* This doesn't actually get used other than for module information */
4657static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004658 {"PNP0700", 0},
4659 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004660};
Joe Perches48c8cee2010-03-10 15:20:45 -08004661
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004662MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4663
Linus Torvalds1da177e2005-04-16 15:20:36 -07004664#else
4665
4666__setup("floppy=", floppy_setup);
4667module_init(floppy_init)
4668#endif
4669
4670MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);