blob: 0cea96ceb78c729033c064653964fe7dd6bebe52 [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
635typedef 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 Perchesa81ee5442010-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 Perchesa81ee5442010-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 Molnar3e541a4a2006-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
Joe Perches48c8cee2010-03-10 15:20:45 -0800911#define LOCK_FDC(drive, interruptible) \
912 if (lock_fdc(drive, interruptible)) \
913 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914
915/* unlocks the driver */
916static inline void unlock_fdc(void)
917{
918 unsigned long flags;
919
920 raw_cmd = NULL;
921 if (!test_bit(0, &fdc_busy))
922 DPRINT("FDC access conflict!\n");
923
924 if (do_floppy)
925 DPRINT("device interrupt still active at FDC release: %p!\n",
926 do_floppy);
927 command_status = FD_COMMAND_NONE;
928 spin_lock_irqsave(&floppy_lock, flags);
929 del_timer(&fd_timeout);
930 cont = NULL;
931 clear_bit(0, &fdc_busy);
Tejun Heo9934c8c2009-05-08 11:54:16 +0900932 if (current_req || blk_peek_request(floppy_queue))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 do_fd_request(floppy_queue);
934 spin_unlock_irqrestore(&floppy_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 wake_up(&fdc_wait);
936}
937
938/* switches the motor off after a given timeout */
939static void motor_off_callback(unsigned long nr)
940{
941 unsigned char mask = ~(0x10 << UNIT(nr));
942
943 set_dor(FDC(nr), mask, 0);
944}
945
946/* schedules motor off */
947static void floppy_off(unsigned int drive)
948{
949 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700950 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
952 if (!(FDCS->dor & (0x10 << UNIT(drive))))
953 return;
954
955 del_timer(motor_off_timer + drive);
956
957 /* make spindle stop in a position which minimizes spinup time
958 * next time */
959 if (UDP->rps) {
960 delta = jiffies - UDRS->first_read_date + HZ -
961 UDP->spindown_offset;
962 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
963 motor_off_timer[drive].expires =
964 jiffies + UDP->spindown - delta;
965 }
966 add_timer(motor_off_timer + drive);
967}
968
969/*
970 * cycle through all N_DRIVE floppy drives, for disk change testing.
971 * stopping at current drive. This is done before any long operation, to
972 * be sure to have up to date disk change information.
973 */
974static void scandrives(void)
975{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700976 int i;
977 int drive;
978 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
980 if (DP->select_delay)
981 return;
982
983 saved_drive = current_drive;
984 for (i = 0; i < N_DRIVE; i++) {
985 drive = (saved_drive + i + 1) % N_DRIVE;
986 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
987 continue; /* skip closed drives */
988 set_fdc(drive);
989 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
990 (0x10 << UNIT(drive))))
991 /* switch the motor off again, if it was off to
992 * begin with */
993 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
994 }
995 set_fdc(saved_drive);
996}
997
998static void empty(void)
999{
1000}
1001
David Howells65f27f32006-11-22 14:55:48 +00001002static DECLARE_WORK(floppy_work, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
Joe Perches48c8cee2010-03-10 15:20:45 -08001004static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005{
David Howells65f27f32006-11-22 14:55:48 +00001006 PREPARE_WORK(&floppy_work, (work_func_t)handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 schedule_work(&floppy_work);
1008}
1009
Ingo Molnar8d06afa2005-09-09 13:10:40 -07001010static DEFINE_TIMER(fd_timer, NULL, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011
1012static void cancel_activity(void)
1013{
1014 unsigned long flags;
1015
1016 spin_lock_irqsave(&floppy_lock, flags);
1017 do_floppy = NULL;
David Howells65f27f32006-11-22 14:55:48 +00001018 PREPARE_WORK(&floppy_work, (work_func_t)empty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 del_timer(&fd_timer);
1020 spin_unlock_irqrestore(&floppy_lock, flags);
1021}
1022
1023/* this function makes sure that the disk stays in the drive during the
1024 * transfer */
1025static void fd_watchdog(void)
1026{
1027#ifdef DCL_DEBUG
Joe Perchesa81ee5442010-03-10 15:20:46 -08001028 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 DPRINT("calling disk change from watchdog\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030#endif
1031
1032 if (disk_change(current_drive)) {
1033 DPRINT("disk removed during i/o\n");
1034 cancel_activity();
1035 cont->done(0);
1036 reset_fdc();
1037 } else {
1038 del_timer(&fd_timer);
1039 fd_timer.function = (timeout_fn) fd_watchdog;
1040 fd_timer.expires = jiffies + HZ / 10;
1041 add_timer(&fd_timer);
1042 }
1043}
1044
1045static void main_command_interrupt(void)
1046{
1047 del_timer(&fd_timer);
1048 cont->interrupt();
1049}
1050
1051/* waits for a delay (spinup or select) to pass */
1052static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
1053{
1054 if (FDCS->reset) {
1055 reset_fdc(); /* do the reset during sleep to win time
1056 * if we don't need to sleep, it's a good
1057 * occasion anyways */
1058 return 1;
1059 }
1060
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001061 if (time_before(jiffies, delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 del_timer(&fd_timer);
1063 fd_timer.function = function;
1064 fd_timer.expires = delay;
1065 add_timer(&fd_timer);
1066 return 1;
1067 }
1068 return 0;
1069}
1070
1071static DEFINE_SPINLOCK(floppy_hlt_lock);
1072static int hlt_disabled;
1073static void floppy_disable_hlt(void)
1074{
1075 unsigned long flags;
1076
1077 spin_lock_irqsave(&floppy_hlt_lock, flags);
1078 if (!hlt_disabled) {
1079 hlt_disabled = 1;
1080#ifdef HAVE_DISABLE_HLT
1081 disable_hlt();
1082#endif
1083 }
1084 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1085}
1086
1087static void floppy_enable_hlt(void)
1088{
1089 unsigned long flags;
1090
1091 spin_lock_irqsave(&floppy_hlt_lock, flags);
1092 if (hlt_disabled) {
1093 hlt_disabled = 0;
1094#ifdef HAVE_DISABLE_HLT
1095 enable_hlt();
1096#endif
1097 }
1098 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1099}
1100
1101static void setup_DMA(void)
1102{
1103 unsigned long f;
1104
1105#ifdef FLOPPY_SANITY_CHECK
1106 if (raw_cmd->length == 0) {
1107 int i;
1108
Joe Perchesb46df352010-03-10 15:20:46 -08001109 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001111 pr_cont("%x,", raw_cmd->cmd[i]);
1112 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 cont->done(0);
1114 FDCS->reset = 1;
1115 return;
1116 }
1117 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001118 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 cont->done(0);
1120 FDCS->reset = 1;
1121 return;
1122 }
1123#endif
1124 f = claim_dma_lock();
1125 fd_disable_dma();
1126#ifdef fd_dma_setup
1127 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1128 (raw_cmd->flags & FD_RAW_READ) ?
1129 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1130 release_dma_lock(f);
1131 cont->done(0);
1132 FDCS->reset = 1;
1133 return;
1134 }
1135 release_dma_lock(f);
1136#else
1137 fd_clear_dma_ff();
1138 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1139 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1140 DMA_MODE_READ : DMA_MODE_WRITE);
1141 fd_set_dma_addr(raw_cmd->kernel_data);
1142 fd_set_dma_count(raw_cmd->length);
1143 virtual_dma_port = FDCS->address;
1144 fd_enable_dma();
1145 release_dma_lock(f);
1146#endif
1147 floppy_disable_hlt();
1148}
1149
1150static void show_floppy(void);
1151
1152/* waits until the fdc becomes ready */
1153static int wait_til_ready(void)
1154{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001155 int status;
1156 int counter;
1157
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 if (FDCS->reset)
1159 return -1;
1160 for (counter = 0; counter < 10000; counter++) {
1161 status = fd_inb(FD_STATUS);
1162 if (status & STATUS_READY)
1163 return status;
1164 }
1165 if (!initialising) {
1166 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1167 show_floppy();
1168 }
1169 FDCS->reset = 1;
1170 return -1;
1171}
1172
1173/* sends a command byte to the fdc */
1174static int output_byte(char byte)
1175{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001176 int status = wait_til_ready();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001178 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 return -1;
1180 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY) {
1181 fd_outb(byte, FD_DATA);
1182#ifdef FLOPPY_SANITY_CHECK
1183 output_log[output_log_pos].data = byte;
1184 output_log[output_log_pos].status = status;
1185 output_log[output_log_pos].jiffies = jiffies;
1186 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
1187#endif
1188 return 0;
1189 }
1190 FDCS->reset = 1;
1191 if (!initialising) {
1192 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1193 byte, fdc, status);
1194 show_floppy();
1195 }
1196 return -1;
1197}
1198
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199/* gets the response from the fdc */
1200static int result(void)
1201{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001202 int i;
1203 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204
1205 for (i = 0; i < MAX_REPLIES; i++) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001206 status = wait_til_ready();
1207 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 break;
1209 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1210 if ((status & ~STATUS_BUSY) == STATUS_READY) {
1211#ifdef FLOPPY_SANITY_CHECK
1212 resultjiffies = jiffies;
1213 resultsize = i;
1214#endif
1215 return i;
1216 }
1217 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1218 reply_buffer[i] = fd_inb(FD_DATA);
1219 else
1220 break;
1221 }
1222 if (!initialising) {
1223 DPRINT
1224 ("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1225 fdc, status, i);
1226 show_floppy();
1227 }
1228 FDCS->reset = 1;
1229 return -1;
1230}
1231
1232#define MORE_OUTPUT -2
1233/* does the fdc need more output? */
1234static int need_more_output(void)
1235{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001236 int status = wait_til_ready();
Jesper Juhl06f748c2007-10-16 23:30:57 -07001237
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001238 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 return -1;
1240 if ((status & (STATUS_READY | STATUS_DIR | STATUS_DMA)) == STATUS_READY)
1241 return MORE_OUTPUT;
1242 return result();
1243}
1244
1245/* Set perpendicular mode as required, based on data rate, if supported.
1246 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1247 */
1248static inline void perpendicular_mode(void)
1249{
1250 unsigned char perp_mode;
1251
1252 if (raw_cmd->rate & 0x40) {
1253 switch (raw_cmd->rate & 3) {
1254 case 0:
1255 perp_mode = 2;
1256 break;
1257 case 3:
1258 perp_mode = 3;
1259 break;
1260 default:
1261 DPRINT("Invalid data rate for perpendicular mode!\n");
1262 cont->done(0);
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001263 FDCS->reset = 1;
1264 /*
1265 * convenient way to return to
1266 * redo without too much hassle
1267 * (deep stack et al.)
1268 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 return;
1270 }
1271 } else
1272 perp_mode = 0;
1273
1274 if (FDCS->perp_mode == perp_mode)
1275 return;
1276 if (FDCS->version >= FDC_82077_ORIG) {
1277 output_byte(FD_PERPENDICULAR);
1278 output_byte(perp_mode);
1279 FDCS->perp_mode = perp_mode;
1280 } else if (perp_mode) {
1281 DPRINT("perpendicular mode not supported by this FDC.\n");
1282 }
1283} /* perpendicular_mode */
1284
1285static int fifo_depth = 0xa;
1286static int no_fifo;
1287
1288static int fdc_configure(void)
1289{
1290 /* Turn on FIFO */
1291 output_byte(FD_CONFIGURE);
1292 if (need_more_output() != MORE_OUTPUT)
1293 return 0;
1294 output_byte(0);
1295 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1296 output_byte(0); /* pre-compensation from track
1297 0 upwards */
1298 return 1;
1299}
1300
1301#define NOMINAL_DTR 500
1302
1303/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1304 * head load time, and DMA disable flag to values needed by floppy.
1305 *
1306 * The value "dtr" is the data transfer rate in Kbps. It is needed
1307 * to account for the data rate-based scaling done by the 82072 and 82077
1308 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1309 * 8272a).
1310 *
1311 * Note that changing the data transfer rate has a (probably deleterious)
1312 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1313 * fdc_specify is called again after each data transfer rate
1314 * change.
1315 *
1316 * srt: 1000 to 16000 in microseconds
1317 * hut: 16 to 240 milliseconds
1318 * hlt: 2 to 254 milliseconds
1319 *
1320 * These values are rounded up to the next highest available delay time.
1321 */
1322static void fdc_specify(void)
1323{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001324 unsigned char spec1;
1325 unsigned char spec2;
1326 unsigned long srt;
1327 unsigned long hlt;
1328 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 unsigned long dtr = NOMINAL_DTR;
1330 unsigned long scale_dtr = NOMINAL_DTR;
1331 int hlt_max_code = 0x7f;
1332 int hut_max_code = 0xf;
1333
1334 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1335 fdc_configure();
1336 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 }
1338
1339 switch (raw_cmd->rate & 0x03) {
1340 case 3:
1341 dtr = 1000;
1342 break;
1343 case 1:
1344 dtr = 300;
1345 if (FDCS->version >= FDC_82078) {
1346 /* chose the default rate table, not the one
1347 * where 1 = 2 Mbps */
1348 output_byte(FD_DRIVESPEC);
1349 if (need_more_output() == MORE_OUTPUT) {
1350 output_byte(UNIT(current_drive));
1351 output_byte(0xc0);
1352 }
1353 }
1354 break;
1355 case 2:
1356 dtr = 250;
1357 break;
1358 }
1359
1360 if (FDCS->version >= FDC_82072) {
1361 scale_dtr = dtr;
1362 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1363 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1364 }
1365
1366 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001367 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee5442010-03-10 15:20:46 -08001368 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 srt = srt / 4;
Joe Perchesa81ee5442010-03-10 15:20:46 -08001370
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 SUPBOUND(srt, 0xf);
1372 INFBOUND(srt, 0);
1373
Julia Lawall061837b2008-09-22 14:57:16 -07001374 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 if (hlt < 0x01)
1376 hlt = 0x01;
1377 else if (hlt > 0x7f)
1378 hlt = hlt_max_code;
1379
Julia Lawall061837b2008-09-22 14:57:16 -07001380 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 if (hut < 0x1)
1382 hut = 0x1;
1383 else if (hut > 0xf)
1384 hut = hut_max_code;
1385
1386 spec1 = (srt << 4) | hut;
1387 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1388
1389 /* If these parameters did not change, just return with success */
1390 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1391 /* Go ahead and set spec1 and spec2 */
1392 output_byte(FD_SPECIFY);
1393 output_byte(FDCS->spec1 = spec1);
1394 output_byte(FDCS->spec2 = spec2);
1395 }
1396} /* fdc_specify */
1397
1398/* Set the FDC's data transfer rate on behalf of the specified drive.
1399 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1400 * of the specify command (i.e. using the fdc_specify function).
1401 */
1402static int fdc_dtr(void)
1403{
1404 /* If data rate not already set to desired value, set it. */
1405 if ((raw_cmd->rate & 3) == FDCS->dtr)
1406 return 0;
1407
1408 /* Set dtr */
1409 fd_outb(raw_cmd->rate & 3, FD_DCR);
1410
1411 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1412 * need a stabilization period of several milliseconds to be
1413 * enforced after data rate changes before R/W operations.
1414 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1415 */
1416 FDCS->dtr = raw_cmd->rate & 3;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001417 return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
1418 (timeout_fn)floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419} /* fdc_dtr */
1420
1421static void tell_sector(void)
1422{
Joe Perchesb46df352010-03-10 15:20:46 -08001423 pr_cont(": track %d, head %d, sector %d, size %d",
1424 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425} /* tell_sector */
1426
Joe Perchesb46df352010-03-10 15:20:46 -08001427static void print_errors(void)
1428{
1429 DPRINT("");
1430 if (ST0 & ST0_ECE) {
1431 pr_cont("Recalibrate failed!");
1432 } else if (ST2 & ST2_CRC) {
1433 pr_cont("data CRC error");
1434 tell_sector();
1435 } else if (ST1 & ST1_CRC) {
1436 pr_cont("CRC error");
1437 tell_sector();
1438 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1439 (ST2 & ST2_MAM)) {
1440 if (!probing) {
1441 pr_cont("sector not found");
1442 tell_sector();
1443 } else
1444 pr_cont("probe failed...");
1445 } else if (ST2 & ST2_WC) { /* seek error */
1446 pr_cont("wrong cylinder");
1447 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1448 pr_cont("bad cylinder");
1449 } else {
1450 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1451 ST0, ST1, ST2);
1452 tell_sector();
1453 }
1454 pr_cont("\n");
1455}
1456
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457/*
1458 * OK, this error interpreting routine is called after a
1459 * DMA read/write has succeeded
1460 * or failed, so we check the results, and copy any buffers.
1461 * hhb: Added better error reporting.
1462 * ak: Made this into a separate routine.
1463 */
1464static int interpret_errors(void)
1465{
1466 char bad;
1467
1468 if (inr != 7) {
1469 DPRINT("-- FDC reply error");
1470 FDCS->reset = 1;
1471 return 1;
1472 }
1473
1474 /* check IC to find cause of interrupt */
1475 switch (ST0 & ST0_INTR) {
1476 case 0x40: /* error occurred during command execution */
1477 if (ST1 & ST1_EOC)
1478 return 0; /* occurs with pseudo-DMA */
1479 bad = 1;
1480 if (ST1 & ST1_WP) {
1481 DPRINT("Drive is write protected\n");
1482 CLEARF(FD_DISK_WRITABLE);
1483 cont->done(0);
1484 bad = 2;
1485 } else if (ST1 & ST1_ND) {
1486 SETF(FD_NEED_TWADDLE);
1487 } else if (ST1 & ST1_OR) {
1488 if (DP->flags & FTD_MSG)
1489 DPRINT("Over/Underrun - retrying\n");
1490 bad = 0;
1491 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001492 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 }
1494 if (ST2 & ST2_WC || ST2 & ST2_BC)
1495 /* wrong cylinder => recal */
1496 DRS->track = NEED_2_RECAL;
1497 return bad;
1498 case 0x80: /* invalid command given */
1499 DPRINT("Invalid FDC command given!\n");
1500 cont->done(0);
1501 return 2;
1502 case 0xc0:
1503 DPRINT("Abnormal termination caused by polling\n");
1504 cont->error();
1505 return 2;
1506 default: /* (0) Normal command termination */
1507 return 0;
1508 }
1509}
1510
1511/*
1512 * This routine is called when everything should be correctly set up
1513 * for the transfer (i.e. floppy motor is on, the correct floppy is
1514 * selected, and the head is sitting on the right track).
1515 */
1516static void setup_rw_floppy(void)
1517{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001518 int i;
1519 int r;
1520 int flags;
1521 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 unsigned long ready_date;
1523 timeout_fn function;
1524
1525 flags = raw_cmd->flags;
1526 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1527 flags |= FD_RAW_INTR;
1528
1529 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1530 ready_date = DRS->spinup_date + DP->spinup;
1531 /* If spinup will take a long time, rerun scandrives
1532 * again just before spinup completion. Beware that
1533 * after scandrives, we must again wait for selection.
1534 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001535 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 ready_date -= DP->select_delay;
1537 function = (timeout_fn) floppy_start;
1538 } else
1539 function = (timeout_fn) setup_rw_floppy;
1540
1541 /* wait until the floppy is spinning fast enough */
1542 if (fd_wait_for_completion(ready_date, function))
1543 return;
1544 }
1545 dflags = DRS->flags;
1546
1547 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1548 setup_DMA();
1549
1550 if (flags & FD_RAW_INTR)
1551 do_floppy = main_command_interrupt;
1552
1553 r = 0;
1554 for (i = 0; i < raw_cmd->cmd_count; i++)
1555 r |= output_byte(raw_cmd->cmd[i]);
1556
1557 debugt("rw_command: ");
1558
1559 if (r) {
1560 cont->error();
1561 reset_fdc();
1562 return;
1563 }
1564
1565 if (!(flags & FD_RAW_INTR)) {
1566 inr = result();
1567 cont->interrupt();
1568 } else if (flags & FD_RAW_NEED_DISK)
1569 fd_watchdog();
1570}
1571
1572static int blind_seek;
1573
1574/*
1575 * This is the routine called after every seek (or recalibrate) interrupt
1576 * from the floppy controller.
1577 */
1578static void seek_interrupt(void)
1579{
1580 debugt("seek interrupt:");
1581 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1582 DPRINT("seek failed\n");
1583 DRS->track = NEED_2_RECAL;
1584 cont->error();
1585 cont->redo();
1586 return;
1587 }
1588 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
1589#ifdef DCL_DEBUG
1590 if (DP->flags & FD_DEBUG) {
Joe Perchesb46df352010-03-10 15:20:46 -08001591 DPRINT("clearing NEWCHANGE flag because of effective seek\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 DPRINT("jiffies=%lu\n", jiffies);
1593 }
1594#endif
1595 CLEARF(FD_DISK_NEWCHANGE); /* effective seek */
1596 DRS->select_date = jiffies;
1597 }
1598 DRS->track = ST1;
1599 floppy_ready();
1600}
1601
1602static void check_wp(void)
1603{
1604 if (TESTF(FD_VERIFY)) {
1605 /* check write protection */
1606 output_byte(FD_GETSTATUS);
1607 output_byte(UNIT(current_drive));
1608 if (result() != 1) {
1609 FDCS->reset = 1;
1610 return;
1611 }
1612 CLEARF(FD_VERIFY);
1613 CLEARF(FD_NEED_TWADDLE);
1614#ifdef DCL_DEBUG
1615 if (DP->flags & FD_DEBUG) {
1616 DPRINT("checking whether disk is write protected\n");
1617 DPRINT("wp=%x\n", ST3 & 0x40);
1618 }
1619#endif
1620 if (!(ST3 & 0x40))
1621 SETF(FD_DISK_WRITABLE);
1622 else
1623 CLEARF(FD_DISK_WRITABLE);
1624 }
1625}
1626
1627static void seek_floppy(void)
1628{
1629 int track;
1630
1631 blind_seek = 0;
1632
1633#ifdef DCL_DEBUG
Joe Perchesa81ee5442010-03-10 15:20:46 -08001634 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 DPRINT("calling disk change from seek\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636#endif
1637
1638 if (!TESTF(FD_DISK_NEWCHANGE) &&
1639 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1640 /* the media changed flag should be cleared after the seek.
1641 * If it isn't, this means that there is really no disk in
1642 * the drive.
1643 */
1644 SETF(FD_DISK_CHANGED);
1645 cont->done(0);
1646 cont->redo();
1647 return;
1648 }
1649 if (DRS->track <= NEED_1_RECAL) {
1650 recalibrate_floppy();
1651 return;
1652 } else if (TESTF(FD_DISK_NEWCHANGE) &&
1653 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1654 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1655 /* we seek to clear the media-changed condition. Does anybody
1656 * know a more elegant way, which works on all drives? */
1657 if (raw_cmd->track)
1658 track = raw_cmd->track - 1;
1659 else {
1660 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1661 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1662 blind_seek = 1;
1663 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1664 }
1665 track = 1;
1666 }
1667 } else {
1668 check_wp();
1669 if (raw_cmd->track != DRS->track &&
1670 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1671 track = raw_cmd->track;
1672 else {
1673 setup_rw_floppy();
1674 return;
1675 }
1676 }
1677
1678 do_floppy = seek_interrupt;
1679 output_byte(FD_SEEK);
1680 output_byte(UNIT(current_drive));
Joe Perches2300f902010-03-10 15:20:49 -08001681 if (output_byte(track) < 0) {
1682 reset_fdc();
1683 return;
1684 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 debugt("seek command:");
1686}
1687
1688static void recal_interrupt(void)
1689{
1690 debugt("recal interrupt:");
1691 if (inr != 2)
1692 FDCS->reset = 1;
1693 else if (ST0 & ST0_ECE) {
1694 switch (DRS->track) {
1695 case NEED_1_RECAL:
1696 debugt("recal interrupt need 1 recal:");
1697 /* after a second recalibrate, we still haven't
1698 * reached track 0. Probably no drive. Raise an
1699 * error, as failing immediately might upset
1700 * computers possessed by the Devil :-) */
1701 cont->error();
1702 cont->redo();
1703 return;
1704 case NEED_2_RECAL:
1705 debugt("recal interrupt need 2 recal:");
1706 /* If we already did a recalibrate,
1707 * and we are not at track 0, this
1708 * means we have moved. (The only way
1709 * not to move at recalibration is to
1710 * be already at track 0.) Clear the
1711 * new change flag */
1712#ifdef DCL_DEBUG
Joe Perchesb46df352010-03-10 15:20:46 -08001713 if (DP->flags & FD_DEBUG)
1714 DPRINT("clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715#endif
1716
1717 CLEARF(FD_DISK_NEWCHANGE);
1718 DRS->select_date = jiffies;
1719 /* fall through */
1720 default:
1721 debugt("recal interrupt default:");
1722 /* Recalibrate moves the head by at
1723 * most 80 steps. If after one
1724 * recalibrate we don't have reached
1725 * track 0, this might mean that we
1726 * started beyond track 80. Try
1727 * again. */
1728 DRS->track = NEED_1_RECAL;
1729 break;
1730 }
1731 } else
1732 DRS->track = ST1;
1733 floppy_ready();
1734}
1735
1736static void print_result(char *message, int inr)
1737{
1738 int i;
1739
1740 DPRINT("%s ", message);
1741 if (inr >= 0)
1742 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001743 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1744 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745}
1746
1747/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001748irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 int do_print;
1751 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001752 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753
1754 lasthandler = handler;
1755 interruptjiffies = jiffies;
1756
1757 f = claim_dma_lock();
1758 fd_disable_dma();
1759 release_dma_lock(f);
1760
1761 floppy_enable_hlt();
1762 do_floppy = NULL;
1763 if (fdc >= N_FDC || FDCS->address == -1) {
1764 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001765 pr_info("DOR0=%x\n", fdc_state[0].dor);
1766 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
1767 pr_info("handler=%p\n", handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 is_alive("bizarre fdc");
1769 return IRQ_NONE;
1770 }
1771
1772 FDCS->reset = 0;
1773 /* We have to clear the reset flag here, because apparently on boxes
1774 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1775 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1776 * emission of the SENSEI's.
1777 * It is OK to emit floppy commands because we are in an interrupt
1778 * handler here, and thus we have to fear no interference of other
1779 * activity.
1780 */
1781
1782 do_print = !handler && print_unex && !initialising;
1783
1784 inr = result();
1785 if (do_print)
1786 print_result("unexpected interrupt", inr);
1787 if (inr == 0) {
1788 int max_sensei = 4;
1789 do {
1790 output_byte(FD_SENSEI);
1791 inr = result();
1792 if (do_print)
1793 print_result("sensei", inr);
1794 max_sensei--;
1795 } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2
1796 && max_sensei);
1797 }
1798 if (!handler) {
1799 FDCS->reset = 1;
1800 return IRQ_NONE;
1801 }
1802 schedule_bh(handler);
1803 is_alive("normal interrupt end");
1804
1805 /* FIXME! Was it really for us? */
1806 return IRQ_HANDLED;
1807}
1808
1809static void recalibrate_floppy(void)
1810{
1811 debugt("recalibrate floppy:");
1812 do_floppy = recal_interrupt;
1813 output_byte(FD_RECALIBRATE);
Joe Perches2300f902010-03-10 15:20:49 -08001814 if (output_byte(UNIT(current_drive)) < 0) {
1815 reset_fdc();
1816 return;
1817 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818}
1819
1820/*
1821 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1822 */
1823static void reset_interrupt(void)
1824{
1825 debugt("reset interrupt:");
1826 result(); /* get the status ready for set_fdc */
1827 if (FDCS->reset) {
Joe Perchesb46df352010-03-10 15:20:46 -08001828 pr_info("reset set in interrupt, calling %p\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 cont->error(); /* a reset just after a reset. BAD! */
1830 }
1831 cont->redo();
1832}
1833
1834/*
1835 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1836 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1837 */
1838static void reset_fdc(void)
1839{
1840 unsigned long flags;
1841
1842 do_floppy = reset_interrupt;
1843 FDCS->reset = 0;
1844 reset_fdc_info(0);
1845
1846 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1847 /* Irrelevant for systems with true DMA (i386). */
1848
1849 flags = claim_dma_lock();
1850 fd_disable_dma();
1851 release_dma_lock(flags);
1852
1853 if (FDCS->version >= FDC_82072A)
1854 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1855 else {
1856 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1857 udelay(FD_RESET_DELAY);
1858 fd_outb(FDCS->dor, FD_DOR);
1859 }
1860}
1861
1862static void show_floppy(void)
1863{
1864 int i;
1865
Joe Perchesb46df352010-03-10 15:20:46 -08001866 pr_info("\n");
1867 pr_info("floppy driver state\n");
1868 pr_info("-------------------\n");
1869 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%p\n",
1870 jiffies, interruptjiffies, jiffies - interruptjiffies,
1871 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872
1873#ifdef FLOPPY_SANITY_CHECK
Joe Perchesb46df352010-03-10 15:20:46 -08001874 pr_info("timeout_message=%s\n", timeout_message);
1875 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001877 pr_info("%2x %2x %lu\n",
1878 output_log[(i + output_log_pos) % OLOGSIZE].data,
1879 output_log[(i + output_log_pos) % OLOGSIZE].status,
1880 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1881 pr_info("last result at %lu\n", resultjiffies);
1882 pr_info("last redo_fd_request at %lu\n", lastredo);
1883 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1884 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885#endif
1886
Joe Perchesb46df352010-03-10 15:20:46 -08001887 pr_info("status=%x\n", fd_inb(FD_STATUS));
1888 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 if (do_floppy)
Joe Perchesb46df352010-03-10 15:20:46 -08001890 pr_info("do_floppy=%p\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001891 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08001892 pr_info("floppy_work.func=%p\n", floppy_work.func);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08001894 pr_info("fd_timer.function=%p\n", fd_timer.function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 if (timer_pending(&fd_timeout)) {
Joe Perchesb46df352010-03-10 15:20:46 -08001896 pr_info("timer_function=%p\n", fd_timeout.function);
1897 pr_info("expires=%lu\n", fd_timeout.expires - jiffies);
1898 pr_info("now=%lu\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 }
Joe Perchesb46df352010-03-10 15:20:46 -08001900 pr_info("cont=%p\n", cont);
1901 pr_info("current_req=%p\n", current_req);
1902 pr_info("command_status=%d\n", command_status);
1903 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904}
1905
1906static void floppy_shutdown(unsigned long data)
1907{
1908 unsigned long flags;
1909
1910 if (!initialising)
1911 show_floppy();
1912 cancel_activity();
1913
1914 floppy_enable_hlt();
1915
1916 flags = claim_dma_lock();
1917 fd_disable_dma();
1918 release_dma_lock(flags);
1919
1920 /* avoid dma going to a random drive after shutdown */
1921
1922 if (!initialising)
1923 DPRINT("floppy timeout called\n");
1924 FDCS->reset = 1;
1925 if (cont) {
1926 cont->done(0);
1927 cont->redo(); /* this will recall reset when needed */
1928 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001929 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 process_fd_request();
1931 }
1932 is_alive("floppy shutdown");
1933}
1934
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001936static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001938 int mask;
1939 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940
1941 mask = 0xfc;
1942 data = UNIT(current_drive);
1943 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1944 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1945 set_debugt();
1946 /* no read since this drive is running */
1947 DRS->first_read_date = 0;
1948 /* note motor start time if motor is not yet running */
1949 DRS->spinup_date = jiffies;
1950 data |= (0x10 << UNIT(current_drive));
1951 }
1952 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1953 mask &= ~(0x10 << UNIT(current_drive));
1954
1955 /* starts motor and selects floppy */
1956 del_timer(motor_off_timer + current_drive);
1957 set_dor(fdc, mask, data);
1958
1959 /* wait_for_completion also schedules reset if needed. */
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001960 return fd_wait_for_completion(DRS->select_date + DP->select_delay,
1961 (timeout_fn)function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962}
1963
1964static void floppy_ready(void)
1965{
Joe Perches045f9832010-03-10 15:20:47 -08001966 if (FDCS->reset) {
1967 reset_fdc();
1968 return;
1969 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 if (start_motor(floppy_ready))
1971 return;
1972 if (fdc_dtr())
1973 return;
1974
1975#ifdef DCL_DEBUG
Joe Perchesa81ee5442010-03-10 15:20:46 -08001976 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 DPRINT("calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978#endif
1979 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1980 disk_change(current_drive) && !DP->select_delay)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001981 twaddle(); /* this clears the dcl on certain
1982 * drive/controller combinations */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983
1984#ifdef fd_chose_dma_mode
1985 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1986 unsigned long flags = claim_dma_lock();
1987 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1988 release_dma_lock(flags);
1989 }
1990#endif
1991
1992 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1993 perpendicular_mode();
1994 fdc_specify(); /* must be done here because of hut, hlt ... */
1995 seek_floppy();
1996 } else {
1997 if ((raw_cmd->flags & FD_RAW_READ) ||
1998 (raw_cmd->flags & FD_RAW_WRITE))
1999 fdc_specify();
2000 setup_rw_floppy();
2001 }
2002}
2003
2004static void floppy_start(void)
2005{
2006 reschedule_timeout(current_reqD, "floppy start", 0);
2007
2008 scandrives();
2009#ifdef DCL_DEBUG
Joe Perchesa81ee5442010-03-10 15:20:46 -08002010 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 DPRINT("setting NEWCHANGE in floppy_start\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012#endif
2013 SETF(FD_DISK_NEWCHANGE);
2014 floppy_ready();
2015}
2016
2017/*
2018 * ========================================================================
2019 * here ends the bottom half. Exported routines are:
2020 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
2021 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
2022 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
2023 * and set_dor.
2024 * ========================================================================
2025 */
2026/*
2027 * General purpose continuations.
2028 * ==============================
2029 */
2030
2031static void do_wakeup(void)
2032{
2033 reschedule_timeout(MAXTIMEOUT, "do wakeup", 0);
2034 cont = NULL;
2035 command_status += 2;
2036 wake_up(&command_done);
2037}
2038
2039static struct cont_t wakeup_cont = {
2040 .interrupt = empty,
2041 .redo = do_wakeup,
2042 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002043 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044};
2045
2046static struct cont_t intr_cont = {
2047 .interrupt = empty,
2048 .redo = process_fd_request,
2049 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002050 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051};
2052
Jesper Juhl06f748c2007-10-16 23:30:57 -07002053static int wait_til_done(void (*handler)(void), int interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054{
2055 int ret;
2056
2057 schedule_bh(handler);
2058
2059 if (command_status < 2 && NO_SIGNAL) {
2060 DECLARE_WAITQUEUE(wait, current);
2061
2062 add_wait_queue(&command_done, &wait);
2063 for (;;) {
2064 set_current_state(interruptible ?
2065 TASK_INTERRUPTIBLE :
2066 TASK_UNINTERRUPTIBLE);
2067
2068 if (command_status >= 2 || !NO_SIGNAL)
2069 break;
2070
2071 is_alive("wait_til_done");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 schedule();
2073 }
2074
2075 set_current_state(TASK_RUNNING);
2076 remove_wait_queue(&command_done, &wait);
2077 }
2078
2079 if (command_status < 2) {
2080 cancel_activity();
2081 cont = &intr_cont;
2082 reset_fdc();
2083 return -EINTR;
2084 }
2085
2086 if (FDCS->reset)
2087 command_status = FD_COMMAND_ERROR;
2088 if (command_status == FD_COMMAND_OKAY)
2089 ret = 0;
2090 else
2091 ret = -EIO;
2092 command_status = FD_COMMAND_NONE;
2093 return ret;
2094}
2095
2096static void generic_done(int result)
2097{
2098 command_status = result;
2099 cont = &wakeup_cont;
2100}
2101
2102static void generic_success(void)
2103{
2104 cont->done(1);
2105}
2106
2107static void generic_failure(void)
2108{
2109 cont->done(0);
2110}
2111
2112static void success_and_wakeup(void)
2113{
2114 generic_success();
2115 cont->redo();
2116}
2117
2118/*
2119 * formatting and rw support.
2120 * ==========================
2121 */
2122
2123static int next_valid_format(void)
2124{
2125 int probed_format;
2126
2127 probed_format = DRS->probed_format;
2128 while (1) {
2129 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2130 DRS->probed_format = 0;
2131 return 1;
2132 }
2133 if (floppy_type[DP->autodetect[probed_format]].sect) {
2134 DRS->probed_format = probed_format;
2135 return 0;
2136 }
2137 probed_format++;
2138 }
2139}
2140
2141static void bad_flp_intr(void)
2142{
2143 int err_count;
2144
2145 if (probing) {
2146 DRS->probed_format++;
2147 if (!next_valid_format())
2148 return;
2149 }
2150 err_count = ++(*errors);
2151 INFBOUND(DRWE->badness, err_count);
2152 if (err_count > DP->max_errors.abort)
2153 cont->done(0);
2154 if (err_count > DP->max_errors.reset)
2155 FDCS->reset = 1;
2156 else if (err_count > DP->max_errors.recal)
2157 DRS->track = NEED_2_RECAL;
2158}
2159
2160static void set_floppy(int drive)
2161{
2162 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002163
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 if (type)
2165 _floppy = floppy_type + type;
2166 else
2167 _floppy = current_type[drive];
2168}
2169
2170/*
2171 * formatting support.
2172 * ===================
2173 */
2174static void format_interrupt(void)
2175{
2176 switch (interpret_errors()) {
2177 case 1:
2178 cont->error();
2179 case 2:
2180 break;
2181 case 0:
2182 cont->done(1);
2183 }
2184 cont->redo();
2185}
2186
2187#define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2)
Joe Perches48c8cee2010-03-10 15:20:45 -08002188#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002190
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191static void setup_format_params(int track)
2192{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002193 int n;
2194 int il;
2195 int count;
2196 int head_shift;
2197 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 struct fparm {
2199 unsigned char track, head, sect, size;
2200 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201
2202 raw_cmd = &default_raw_cmd;
2203 raw_cmd->track = track;
2204
Joe Perches48c8cee2010-03-10 15:20:45 -08002205 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2206 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 raw_cmd->rate = _floppy->rate & 0x43;
2208 raw_cmd->cmd_count = NR_F;
2209 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2210 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2211 F_SIZECODE = FD_SIZECODE(_floppy);
2212 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2213 F_GAP = _floppy->fmt_gap;
2214 F_FILL = FD_FILL_BYTE;
2215
2216 raw_cmd->kernel_data = floppy_track_buffer;
2217 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2218
2219 /* allow for about 30ms for data transport per track */
2220 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2221
2222 /* a ``cylinder'' is two tracks plus a little stepping time */
2223 track_shift = 2 * head_shift + 3;
2224
2225 /* position of logical sector 1 on this track */
2226 n = (track_shift * format_req.track + head_shift * format_req.head)
2227 % F_SECT_PER_TRACK;
2228
2229 /* determine interleave */
2230 il = 1;
2231 if (_floppy->fmt_gap < 0x22)
2232 il++;
2233
2234 /* initialize field */
2235 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2236 here[count].track = format_req.track;
2237 here[count].head = format_req.head;
2238 here[count].sect = 0;
2239 here[count].size = F_SIZECODE;
2240 }
2241 /* place logical sectors */
2242 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2243 here[n].sect = count;
2244 n = (n + il) % F_SECT_PER_TRACK;
2245 if (here[n].sect) { /* sector busy, find next free sector */
2246 ++n;
2247 if (n >= F_SECT_PER_TRACK) {
2248 n -= F_SECT_PER_TRACK;
2249 while (here[n].sect)
2250 ++n;
2251 }
2252 }
2253 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002254 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002256 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 }
2258}
2259
2260static void redo_format(void)
2261{
2262 buffer_track = -1;
2263 setup_format_params(format_req.track << STRETCH(_floppy));
2264 floppy_start();
2265 debugt("queue format request");
2266}
2267
2268static struct cont_t format_cont = {
2269 .interrupt = format_interrupt,
2270 .redo = redo_format,
2271 .error = bad_flp_intr,
2272 .done = generic_done
2273};
2274
2275static int do_format(int drive, struct format_descr *tmp_format_req)
2276{
2277 int ret;
2278
2279 LOCK_FDC(drive, 1);
2280 set_floppy(drive);
2281 if (!_floppy ||
2282 _floppy->track > DP->tracks ||
2283 tmp_format_req->track >= _floppy->track ||
2284 tmp_format_req->head >= _floppy->head ||
2285 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2286 !_floppy->fmt_gap) {
2287 process_fd_request();
2288 return -EINVAL;
2289 }
2290 format_req = *tmp_format_req;
2291 format_errors = 0;
2292 cont = &format_cont;
2293 errors = &format_errors;
2294 IWAIT(redo_format);
2295 process_fd_request();
2296 return ret;
2297}
2298
2299/*
2300 * Buffer read/write and support
2301 * =============================
2302 */
2303
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002304static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305{
2306 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002307 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308
2309 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002310 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002311 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002312 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314
2315 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002316 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 current_req = NULL;
2318}
2319
2320/* new request_done. Can handle physical sectors which are smaller than a
2321 * logical buffer */
2322static void request_done(int uptodate)
2323{
2324 struct request_queue *q = floppy_queue;
2325 struct request *req = current_req;
2326 unsigned long flags;
2327 int block;
2328
2329 probing = 0;
Joe Perchesb46df352010-03-10 15:20:46 -08002330 reschedule_timeout(MAXTIMEOUT, "request done", uptodate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331
2332 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002333 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 return;
2335 }
2336
2337 if (uptodate) {
2338 /* maintain values for invalidation on geometry
2339 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002340 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 INFBOUND(DRS->maxblock, block);
2342 if (block > _floppy->sect)
2343 DRS->maxtrack = 1;
2344
2345 /* unlock chained buffers */
2346 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002347 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 spin_unlock_irqrestore(q->queue_lock, flags);
2349 } else {
2350 if (rq_data_dir(req) == WRITE) {
2351 /* record write error information */
2352 DRWE->write_errors++;
2353 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002354 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 DRWE->first_error_generation = DRS->generation;
2356 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002357 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 DRWE->last_error_generation = DRS->generation;
2359 }
2360 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002361 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 spin_unlock_irqrestore(q->queue_lock, flags);
2363 }
2364}
2365
2366/* Interrupt handler evaluating the result of the r/w operation */
2367static void rw_interrupt(void)
2368{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002369 int eoc;
2370 int ssize;
2371 int heads;
2372 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373
2374 if (R_HEAD >= 2) {
2375 /* some Toshiba floppy controllers occasionnally seem to
2376 * return bogus interrupts after read/write operations, which
2377 * can be recognized by a bad head number (>= 2) */
2378 return;
2379 }
2380
2381 if (!DRS->first_read_date)
2382 DRS->first_read_date = jiffies;
2383
2384 nr_sectors = 0;
2385 CODE2SIZE;
2386
2387 if (ST1 & ST1_EOC)
2388 eoc = 1;
2389 else
2390 eoc = 0;
2391
2392 if (COMMAND & 0x80)
2393 heads = 2;
2394 else
2395 heads = 1;
2396
2397 nr_sectors = (((R_TRACK - TRACK) * heads +
2398 R_HEAD - HEAD) * SECT_PER_TRACK +
2399 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2400
2401#ifdef FLOPPY_SANITY_CHECK
2402 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002403 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 DPRINT("long rw: %x instead of %lx\n",
2405 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002406 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2407 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2408 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2409 pr_info("heads=%d eoc=%d\n", heads, eoc);
2410 pr_info("spt=%d st=%d ss=%d\n",
2411 SECT_PER_TRACK, fsector_t, ssize);
2412 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 }
2414#endif
2415
2416 nr_sectors -= in_sector_offset;
2417 INFBOUND(nr_sectors, 0);
2418 SUPBOUND(current_count_sectors, nr_sectors);
2419
2420 switch (interpret_errors()) {
2421 case 2:
2422 cont->redo();
2423 return;
2424 case 1:
2425 if (!current_count_sectors) {
2426 cont->error();
2427 cont->redo();
2428 return;
2429 }
2430 break;
2431 case 0:
2432 if (!current_count_sectors) {
2433 cont->redo();
2434 return;
2435 }
2436 current_type[current_drive] = _floppy;
2437 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2438 break;
2439 }
2440
2441 if (probing) {
2442 if (DP->flags & FTD_MSG)
2443 DPRINT("Auto-detected floppy type %s in fd%d\n",
2444 _floppy->name, current_drive);
2445 current_type[current_drive] = _floppy;
2446 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2447 probing = 0;
2448 }
2449
2450 if (CT(COMMAND) != FD_READ ||
2451 raw_cmd->kernel_data == current_req->buffer) {
2452 /* transfer directly from buffer */
2453 cont->done(1);
2454 } else if (CT(COMMAND) == FD_READ) {
2455 buffer_track = raw_cmd->track;
2456 buffer_drive = current_drive;
2457 INFBOUND(buffer_max, nr_sectors + fsector_t);
2458 }
2459 cont->redo();
2460}
2461
2462/* Compute maximal contiguous buffer size. */
2463static int buffer_chain_size(void)
2464{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 struct bio_vec *bv;
NeilBrown5705f702007-09-25 12:35:59 +02002466 int size;
2467 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 char *base;
2469
2470 base = bio_data(current_req->bio);
2471 size = 0;
2472
NeilBrown5705f702007-09-25 12:35:59 +02002473 rq_for_each_segment(bv, current_req, iter) {
2474 if (page_address(bv->bv_page) + bv->bv_offset != base + size)
2475 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476
NeilBrown5705f702007-09-25 12:35:59 +02002477 size += bv->bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 }
2479
2480 return size >> 9;
2481}
2482
2483/* Compute the maximal transfer size */
2484static int transfer_size(int ssize, int max_sector, int max_size)
2485{
2486 SUPBOUND(max_sector, fsector_t + max_size);
2487
2488 /* alignment */
2489 max_sector -= (max_sector % _floppy->sect) % ssize;
2490
2491 /* transfer size, beginning not aligned */
2492 current_count_sectors = max_sector - fsector_t;
2493
2494 return max_sector;
2495}
2496
2497/*
2498 * Move data from/to the track buffer to/from the buffer cache.
2499 */
2500static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2501{
2502 int remaining; /* number of transferred 512-byte sectors */
2503 struct bio_vec *bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002504 char *buffer;
2505 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002506 int size;
2507 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508
2509 max_sector = transfer_size(ssize,
2510 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002511 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512
2513 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002514 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002516 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517
2518 remaining = current_count_sectors << 9;
2519#ifdef FLOPPY_SANITY_CHECK
Tejun Heo1011c1b2009-05-07 22:24:45 +09002520 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002522 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2523 pr_info("remaining=%d\n", remaining >> 9);
2524 pr_info("current_req->nr_sectors=%u\n",
2525 blk_rq_sectors(current_req));
2526 pr_info("current_req->current_nr_sectors=%u\n",
2527 blk_rq_cur_sectors(current_req));
2528 pr_info("max_sector=%d\n", max_sector);
2529 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 }
2531#endif
2532
2533 buffer_max = max(max_sector, buffer_max);
2534
2535 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2536
Tejun Heo1011c1b2009-05-07 22:24:45 +09002537 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538
NeilBrown5705f702007-09-25 12:35:59 +02002539 rq_for_each_segment(bv, current_req, iter) {
2540 if (!remaining)
2541 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542
NeilBrown5705f702007-09-25 12:35:59 +02002543 size = bv->bv_len;
2544 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545
NeilBrown5705f702007-09-25 12:35:59 +02002546 buffer = page_address(bv->bv_page) + bv->bv_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547#ifdef FLOPPY_SANITY_CHECK
NeilBrown5705f702007-09-25 12:35:59 +02002548 if (dma_buffer + size >
2549 floppy_track_buffer + (max_buffer_sectors << 10) ||
2550 dma_buffer < floppy_track_buffer) {
2551 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002552 (int)((floppy_track_buffer - dma_buffer) >> 9));
2553 pr_info("fsector_t=%d buffer_min=%d\n",
2554 fsector_t, buffer_min);
2555 pr_info("current_count_sectors=%ld\n",
2556 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002558 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002559 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002560 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002561 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 }
NeilBrown5705f702007-09-25 12:35:59 +02002563 if (((unsigned long)buffer) % 512)
2564 DPRINT("%p buffer not aligned\n", buffer);
2565#endif
2566 if (CT(COMMAND) == FD_READ)
2567 memcpy(buffer, dma_buffer, size);
2568 else
2569 memcpy(dma_buffer, buffer, size);
2570
2571 remaining -= size;
2572 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 }
2574#ifdef FLOPPY_SANITY_CHECK
2575 if (remaining) {
2576 if (remaining > 0)
2577 max_sector -= remaining >> 9;
2578 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2579 }
2580#endif
2581}
2582
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583/* work around a bug in pseudo DMA
2584 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2585 * sending data. Hence we need a different way to signal the
2586 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2587 * does not work with MT, hence we can only transfer one head at
2588 * a time
2589 */
2590static void virtualdmabug_workaround(void)
2591{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002592 int hard_sectors;
2593 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594
2595 if (CT(COMMAND) == FD_WRITE) {
2596 COMMAND &= ~0x80; /* switch off multiple track mode */
2597
2598 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2599 end_sector = SECTOR + hard_sectors - 1;
2600#ifdef FLOPPY_SANITY_CHECK
2601 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002602 pr_info("too many sectors %d > %d\n",
2603 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 return;
2605 }
2606#endif
Joe Perches48c8cee2010-03-10 15:20:45 -08002607 SECT_PER_TRACK = end_sector;
2608 /* make sure SECT_PER_TRACK
2609 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 }
2611}
2612
2613/*
2614 * Formulate a read/write request.
2615 * this routine decides where to load the data (directly to buffer, or to
2616 * tmp floppy area), how much data to load (the size of the buffer, the whole
2617 * track, or a single sector)
2618 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2619 * allocation on the fly, it should be done here. No other part should need
2620 * modification.
2621 */
2622
2623static int make_raw_rw_request(void)
2624{
2625 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002626 int max_sector;
2627 int max_size;
2628 int tracksize;
2629 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630
2631 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002632 pr_info("VFS: Block I/O scheduled on unopened device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 return 0;
2634 }
2635
2636 set_fdc((long)current_req->rq_disk->private_data);
2637
2638 raw_cmd = &default_raw_cmd;
2639 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
2640 FD_RAW_NEED_SEEK;
2641 raw_cmd->cmd_count = NR_RW;
2642 if (rq_data_dir(current_req) == READ) {
2643 raw_cmd->flags |= FD_RAW_READ;
2644 COMMAND = FM_MODE(_floppy, FD_READ);
2645 } else if (rq_data_dir(current_req) == WRITE) {
2646 raw_cmd->flags |= FD_RAW_WRITE;
2647 COMMAND = FM_MODE(_floppy, FD_WRITE);
2648 } else {
2649 DPRINT("make_raw_rw_request: unknown command\n");
2650 return 0;
2651 }
2652
2653 max_sector = _floppy->sect * _floppy->head;
2654
Tejun Heo83096eb2009-05-07 22:24:39 +09002655 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2656 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002658 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 current_count_sectors = 1;
2660 return 1;
2661 } else
2662 return 0;
2663 }
2664 HEAD = fsector_t / _floppy->sect;
2665
Keith Wansbrough9e491842008-09-22 14:57:17 -07002666 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 TESTF(FD_NEED_TWADDLE)) && fsector_t < _floppy->sect)
2668 max_sector = _floppy->sect;
2669
2670 /* 2M disks have phantom sectors on the first track */
2671 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2672 max_sector = 2 * _floppy->sect / 3;
2673 if (fsector_t >= max_sector) {
2674 current_count_sectors =
2675 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002676 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 return 1;
2678 }
2679 SIZECODE = 2;
2680 } else
2681 SIZECODE = FD_SIZECODE(_floppy);
2682 raw_cmd->rate = _floppy->rate & 0x43;
2683 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2684 raw_cmd->rate = 1;
2685
2686 if (SIZECODE)
2687 SIZECODE2 = 0xff;
2688 else
2689 SIZECODE2 = 0x80;
2690 raw_cmd->track = TRACK << STRETCH(_floppy);
2691 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2692 GAP = _floppy->gap;
2693 CODE2SIZE;
2694 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2695 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002696 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697
2698 /* tracksize describes the size which can be filled up with sectors
2699 * of size ssize.
2700 */
2701 tracksize = _floppy->sect - _floppy->sect % ssize;
2702 if (tracksize < _floppy->sect) {
2703 SECT_PER_TRACK++;
2704 if (tracksize <= fsector_t % _floppy->sect)
2705 SECTOR--;
2706
2707 /* if we are beyond tracksize, fill up using smaller sectors */
2708 while (tracksize <= fsector_t % _floppy->sect) {
2709 while (tracksize + ssize > _floppy->sect) {
2710 SIZECODE--;
2711 ssize >>= 1;
2712 }
2713 SECTOR++;
2714 SECT_PER_TRACK++;
2715 tracksize += ssize;
2716 }
2717 max_sector = HEAD * _floppy->sect + tracksize;
2718 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2719 max_sector = _floppy->sect;
2720 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2721 /* for virtual DMA bug workaround */
2722 max_sector = _floppy->sect;
2723 }
2724
2725 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2726 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002727 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 if ((raw_cmd->track == buffer_track) &&
2729 (current_drive == buffer_drive) &&
2730 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2731 /* data already in track buffer */
2732 if (CT(COMMAND) == FD_READ) {
2733 copy_buffer(1, max_sector, buffer_max);
2734 return 1;
2735 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002736 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 if (CT(COMMAND) == FD_WRITE) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002738 unsigned int sectors;
2739
2740 sectors = fsector_t + blk_rq_sectors(current_req);
2741 if (sectors > ssize && sectors < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 max_size = ssize + ssize;
2743 else
2744 max_size = ssize;
2745 }
2746 raw_cmd->flags &= ~FD_RAW_WRITE;
2747 raw_cmd->flags |= FD_RAW_READ;
2748 COMMAND = FM_MODE(_floppy, FD_READ);
2749 } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) {
2750 unsigned long dma_limit;
2751 int direct, indirect;
2752
2753 indirect =
2754 transfer_size(ssize, max_sector,
2755 max_buffer_sectors * 2) - fsector_t;
2756
2757 /*
2758 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2759 * on a 64 bit machine!
2760 */
2761 max_size = buffer_chain_size();
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002762 dma_limit = (MAX_DMA_ADDRESS -
2763 ((unsigned long)current_req->buffer)) >> 9;
Joe Perchesa81ee5442010-03-10 15:20:46 -08002764 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 /* 64 kb boundaries */
2767 if (CROSS_64KB(current_req->buffer, max_size << 9))
2768 max_size = (K_64 -
2769 ((unsigned long)current_req->buffer) %
2770 K_64) >> 9;
2771 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2772 /*
2773 * We try to read tracks, but if we get too many errors, we
2774 * go back to reading just one sector at a time.
2775 *
2776 * This means we should be able to read a sector even if there
2777 * are other bad sectors on this track.
2778 */
2779 if (!direct ||
2780 (indirect * 2 > direct * 3 &&
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002781 *errors < DP->max_errors.read_track &&
2782 ((!probing ||
2783 (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002784 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 } else {
2786 raw_cmd->kernel_data = current_req->buffer;
2787 raw_cmd->length = current_count_sectors << 9;
2788 if (raw_cmd->length == 0) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002789 DPRINT("zero dma transfer attempted from make_raw_request\n");
2790 DPRINT("indirect=%d direct=%d fsector_t=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 indirect, direct, fsector_t);
2792 return 0;
2793 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 virtualdmabug_workaround();
2795 return 2;
2796 }
2797 }
2798
2799 if (CT(COMMAND) == FD_READ)
2800 max_size = max_sector; /* unbounded */
2801
2802 /* claim buffer track if needed */
2803 if (buffer_track != raw_cmd->track || /* bad track */
2804 buffer_drive != current_drive || /* bad drive */
2805 fsector_t > buffer_max ||
2806 fsector_t < buffer_min ||
2807 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002808 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 max_sector > 2 * max_buffer_sectors + buffer_min &&
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002810 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
2811 /* not enough space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 buffer_track = -1;
2813 buffer_drive = current_drive;
2814 buffer_max = buffer_min = aligned_sector_t;
2815 }
2816 raw_cmd->kernel_data = floppy_track_buffer +
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002817 ((aligned_sector_t - buffer_min) << 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818
2819 if (CT(COMMAND) == FD_WRITE) {
2820 /* copy write buffer to track buffer.
2821 * if we get here, we know that the write
2822 * is either aligned or the data already in the buffer
2823 * (buffer will be overwritten) */
2824#ifdef FLOPPY_SANITY_CHECK
2825 if (in_sector_offset && buffer_track == -1)
2826 DPRINT("internal error offset !=0 on write\n");
2827#endif
2828 buffer_track = raw_cmd->track;
2829 buffer_drive = current_drive;
2830 copy_buffer(ssize, max_sector,
2831 2 * max_buffer_sectors + buffer_min);
2832 } else
2833 transfer_size(ssize, max_sector,
2834 2 * max_buffer_sectors + buffer_min -
2835 aligned_sector_t);
2836
2837 /* round up current_count_sectors to get dma xfer size */
2838 raw_cmd->length = in_sector_offset + current_count_sectors;
2839 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2840 raw_cmd->length <<= 9;
2841#ifdef FLOPPY_SANITY_CHECK
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 if ((raw_cmd->length < current_count_sectors << 9) ||
2843 (raw_cmd->kernel_data != current_req->buffer &&
2844 CT(COMMAND) == FD_WRITE &&
2845 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2846 aligned_sector_t < buffer_min)) ||
2847 raw_cmd->length % (128 << SIZECODE) ||
2848 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2849 DPRINT("fractionary current count b=%lx s=%lx\n",
2850 raw_cmd->length, current_count_sectors);
2851 if (raw_cmd->kernel_data != current_req->buffer)
Joe Perchesb46df352010-03-10 15:20:46 -08002852 pr_info("addr=%d, length=%ld\n",
2853 (int)((raw_cmd->kernel_data -
2854 floppy_track_buffer) >> 9),
2855 current_count_sectors);
2856 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2857 fsector_t, aligned_sector_t, max_sector, max_size);
2858 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2859 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2860 COMMAND, SECTOR, HEAD, TRACK);
2861 pr_info("buffer drive=%d\n", buffer_drive);
2862 pr_info("buffer track=%d\n", buffer_track);
2863 pr_info("buffer_min=%d\n", buffer_min);
2864 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 return 0;
2866 }
2867
2868 if (raw_cmd->kernel_data != current_req->buffer) {
2869 if (raw_cmd->kernel_data < floppy_track_buffer ||
2870 current_count_sectors < 0 ||
2871 raw_cmd->length < 0 ||
2872 raw_cmd->kernel_data + raw_cmd->length >
2873 floppy_track_buffer + (max_buffer_sectors << 10)) {
2874 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002875 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2876 fsector_t, buffer_min, raw_cmd->length >> 9);
2877 pr_info("current_count_sectors=%ld\n",
2878 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002880 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002882 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 return 0;
2884 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002885 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002886 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 DPRINT("buffer overrun in direct transfer\n");
2888 return 0;
2889 } else if (raw_cmd->length < current_count_sectors << 9) {
2890 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002891 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2892 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 }
2894 if (raw_cmd->length == 0) {
2895 DPRINT("zero dma transfer attempted from make_raw_request\n");
2896 return 0;
2897 }
2898#endif
2899
2900 virtualdmabug_workaround();
2901 return 2;
2902}
2903
2904static void redo_fd_request(void)
2905{
2906#define REPEAT {request_done(0); continue; }
2907 int drive;
2908 int tmp;
2909
2910 lastredo = jiffies;
2911 if (current_drive < N_DRIVE)
2912 floppy_off(current_drive);
2913
2914 for (;;) {
2915 if (!current_req) {
2916 struct request *req;
2917
2918 spin_lock_irq(floppy_queue->queue_lock);
Tejun Heo9934c8c2009-05-08 11:54:16 +09002919 req = blk_fetch_request(floppy_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 spin_unlock_irq(floppy_queue->queue_lock);
2921 if (!req) {
2922 do_floppy = NULL;
2923 unlock_fdc();
2924 return;
2925 }
2926 current_req = req;
2927 }
2928 drive = (long)current_req->rq_disk->private_data;
2929 set_fdc(drive);
2930 reschedule_timeout(current_reqD, "redo fd request", 0);
2931
2932 set_floppy(drive);
2933 raw_cmd = &default_raw_cmd;
2934 raw_cmd->flags = 0;
2935 if (start_motor(redo_fd_request))
2936 return;
2937 disk_change(current_drive);
2938 if (test_bit(current_drive, &fake_change) ||
2939 TESTF(FD_DISK_CHANGED)) {
2940 DPRINT("disk absent or changed during operation\n");
2941 REPEAT;
2942 }
2943 if (!_floppy) { /* Autodetection */
2944 if (!probing) {
2945 DRS->probed_format = 0;
2946 if (next_valid_format()) {
2947 DPRINT("no autodetectable formats\n");
2948 _floppy = NULL;
2949 REPEAT;
2950 }
2951 }
2952 probing = 1;
2953 _floppy =
2954 floppy_type + DP->autodetect[DRS->probed_format];
2955 } else
2956 probing = 0;
2957 errors = &(current_req->errors);
2958 tmp = make_raw_rw_request();
2959 if (tmp < 2) {
2960 request_done(tmp);
2961 continue;
2962 }
2963
2964 if (TESTF(FD_NEED_TWADDLE))
2965 twaddle();
2966 schedule_bh(floppy_start);
2967 debugt("queue fd request");
2968 return;
2969 }
2970#undef REPEAT
2971}
2972
2973static struct cont_t rw_cont = {
2974 .interrupt = rw_interrupt,
2975 .redo = redo_fd_request,
2976 .error = bad_flp_intr,
2977 .done = request_done
2978};
2979
2980static void process_fd_request(void)
2981{
2982 cont = &rw_cont;
2983 schedule_bh(redo_fd_request);
2984}
2985
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002986static void do_fd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987{
2988 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002989 pr_info("VFS: do_fd_request called on non-open device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 return;
2991 }
2992
2993 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002994 pr_info("warning: usage count=0, current_req=%p exiting\n",
2995 current_req);
2996 pr_info("sect=%ld type=%x flags=%x\n",
2997 (long)blk_rq_pos(current_req), current_req->cmd_type,
2998 current_req->cmd_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 return;
3000 }
3001 if (test_bit(0, &fdc_busy)) {
3002 /* fdc busy, this new request will be treated when the
3003 current one is done */
3004 is_alive("do fd request, old request running");
3005 return;
3006 }
3007 lock_fdc(MAXTIMEOUT, 0);
3008 process_fd_request();
3009 is_alive("do fd request");
3010}
3011
3012static struct cont_t poll_cont = {
3013 .interrupt = success_and_wakeup,
3014 .redo = floppy_ready,
3015 .error = generic_failure,
3016 .done = generic_done
3017};
3018
3019static int poll_drive(int interruptible, int flag)
3020{
3021 int ret;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003022
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 /* no auto-sense, just clear dcl */
3024 raw_cmd = &default_raw_cmd;
3025 raw_cmd->flags = flag;
3026 raw_cmd->track = 0;
3027 raw_cmd->cmd_count = 0;
3028 cont = &poll_cont;
3029#ifdef DCL_DEBUG
Joe Perchesa81ee5442010-03-10 15:20:46 -08003030 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 DPRINT("setting NEWCHANGE in poll_drive\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032#endif
3033 SETF(FD_DISK_NEWCHANGE);
3034 WAIT(floppy_ready);
3035 return ret;
3036}
3037
3038/*
3039 * User triggered reset
3040 * ====================
3041 */
3042
3043static void reset_intr(void)
3044{
Joe Perchesb46df352010-03-10 15:20:46 -08003045 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046}
3047
3048static struct cont_t reset_cont = {
3049 .interrupt = reset_intr,
3050 .redo = success_and_wakeup,
3051 .error = generic_failure,
3052 .done = generic_done
3053};
3054
3055static int user_reset_fdc(int drive, int arg, int interruptible)
3056{
3057 int ret;
3058
3059 ret = 0;
3060 LOCK_FDC(drive, interruptible);
3061 if (arg == FD_RESET_ALWAYS)
3062 FDCS->reset = 1;
3063 if (FDCS->reset) {
3064 cont = &reset_cont;
3065 WAIT(reset_fdc);
3066 }
3067 process_fd_request();
3068 return ret;
3069}
3070
3071/*
3072 * Misc Ioctl's and support
3073 * ========================
3074 */
3075static inline int fd_copyout(void __user *param, const void *address,
3076 unsigned long size)
3077{
3078 return copy_to_user(param, address, size) ? -EFAULT : 0;
3079}
3080
Joe Perches48c8cee2010-03-10 15:20:45 -08003081static inline int fd_copyin(void __user *param, void *address,
3082 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083{
3084 return copy_from_user(address, param, size) ? -EFAULT : 0;
3085}
3086
Joe Perches48c8cee2010-03-10 15:20:45 -08003087#define _COPYOUT(x) (copy_to_user((void __user *)param, &(x), sizeof(x)) \
3088 ? -EFAULT : 0)
3089#define _COPYIN(x) (copy_from_user(&(x), (void __user *)param, sizeof(x)) \
3090 ? -EFAULT : 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091
Joe Perches48c8cee2010-03-10 15:20:45 -08003092#define COPYOUT(x) ECALL(_COPYOUT(x))
3093#define COPYIN(x) ECALL(_COPYIN(x))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094
3095static inline const char *drive_name(int type, int drive)
3096{
3097 struct floppy_struct *floppy;
3098
3099 if (type)
3100 floppy = floppy_type + type;
3101 else {
3102 if (UDP->native_format)
3103 floppy = floppy_type + UDP->native_format;
3104 else
3105 return "(null)";
3106 }
3107 if (floppy->name)
3108 return floppy->name;
3109 else
3110 return "(null)";
3111}
3112
3113/* raw commands */
3114static void raw_cmd_done(int flag)
3115{
3116 int i;
3117
3118 if (!flag) {
3119 raw_cmd->flags |= FD_RAW_FAILURE;
3120 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3121 } else {
3122 raw_cmd->reply_count = inr;
3123 if (raw_cmd->reply_count > MAX_REPLIES)
3124 raw_cmd->reply_count = 0;
3125 for (i = 0; i < raw_cmd->reply_count; i++)
3126 raw_cmd->reply[i] = reply_buffer[i];
3127
3128 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3129 unsigned long flags;
3130 flags = claim_dma_lock();
3131 raw_cmd->length = fd_get_dma_residue();
3132 release_dma_lock(flags);
3133 }
3134
3135 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3136 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3137 raw_cmd->flags |= FD_RAW_FAILURE;
3138
3139 if (disk_change(current_drive))
3140 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3141 else
3142 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3143 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3144 motor_off_callback(current_drive);
3145
3146 if (raw_cmd->next &&
3147 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3148 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3149 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3150 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3151 raw_cmd = raw_cmd->next;
3152 return;
3153 }
3154 }
3155 generic_done(flag);
3156}
3157
3158static struct cont_t raw_cmd_cont = {
3159 .interrupt = success_and_wakeup,
3160 .redo = floppy_start,
3161 .error = generic_failure,
3162 .done = raw_cmd_done
3163};
3164
3165static inline int raw_cmd_copyout(int cmd, char __user *param,
3166 struct floppy_raw_cmd *ptr)
3167{
3168 int ret;
3169
3170 while (ptr) {
3171 COPYOUT(*ptr);
3172 param += sizeof(struct floppy_raw_cmd);
3173 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003174 if (ptr->length >= 0 &&
3175 ptr->length <= ptr->buffer_length) {
3176 long length = ptr->buffer_length - ptr->length;
3177 ECALL(fd_copyout(ptr->data, ptr->kernel_data,
3178 length));
3179 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180 }
3181 ptr = ptr->next;
3182 }
3183 return 0;
3184}
3185
3186static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3187{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003188 struct floppy_raw_cmd *next;
3189 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190
3191 this = *ptr;
3192 *ptr = NULL;
3193 while (this) {
3194 if (this->buffer_length) {
3195 fd_dma_mem_free((unsigned long)this->kernel_data,
3196 this->buffer_length);
3197 this->buffer_length = 0;
3198 }
3199 next = this->next;
3200 kfree(this);
3201 this = next;
3202 }
3203}
3204
3205static inline int raw_cmd_copyin(int cmd, char __user *param,
3206 struct floppy_raw_cmd **rcmd)
3207{
3208 struct floppy_raw_cmd *ptr;
3209 int ret;
3210 int i;
3211
3212 *rcmd = NULL;
3213 while (1) {
3214 ptr = (struct floppy_raw_cmd *)
3215 kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3216 if (!ptr)
3217 return -ENOMEM;
3218 *rcmd = ptr;
3219 COPYIN(*ptr);
3220 ptr->next = NULL;
3221 ptr->buffer_length = 0;
3222 param += sizeof(struct floppy_raw_cmd);
3223 if (ptr->cmd_count > 33)
3224 /* the command may now also take up the space
3225 * initially intended for the reply & the
3226 * reply count. Needed for long 82078 commands
3227 * such as RESTORE, which takes ... 17 command
3228 * bytes. Murphy's law #137: When you reserve
3229 * 16 bytes for a structure, you'll one day
3230 * discover that you really need 17...
3231 */
3232 return -EINVAL;
3233
3234 for (i = 0; i < 16; i++)
3235 ptr->reply[i] = 0;
3236 ptr->resultcode = 0;
3237 ptr->kernel_data = NULL;
3238
3239 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3240 if (ptr->length <= 0)
3241 return -EINVAL;
3242 ptr->kernel_data =
3243 (char *)fd_dma_mem_alloc(ptr->length);
3244 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3245 if (!ptr->kernel_data)
3246 return -ENOMEM;
3247 ptr->buffer_length = ptr->length;
3248 }
3249 if (ptr->flags & FD_RAW_WRITE)
3250 ECALL(fd_copyin(ptr->data, ptr->kernel_data,
3251 ptr->length));
3252 rcmd = &(ptr->next);
3253 if (!(ptr->flags & FD_RAW_MORE))
3254 return 0;
3255 ptr->rate &= 0x43;
3256 }
3257}
3258
3259static int raw_cmd_ioctl(int cmd, void __user *param)
3260{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003262 int drive;
3263 int ret2;
3264 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265
3266 if (FDCS->rawcmd <= 1)
3267 FDCS->rawcmd = 1;
3268 for (drive = 0; drive < N_DRIVE; drive++) {
3269 if (FDC(drive) != fdc)
3270 continue;
3271 if (drive == current_drive) {
3272 if (UDRS->fd_ref > 1) {
3273 FDCS->rawcmd = 2;
3274 break;
3275 }
3276 } else if (UDRS->fd_ref) {
3277 FDCS->rawcmd = 2;
3278 break;
3279 }
3280 }
3281
3282 if (FDCS->reset)
3283 return -EIO;
3284
3285 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3286 if (ret) {
3287 raw_cmd_free(&my_raw_cmd);
3288 return ret;
3289 }
3290
3291 raw_cmd = my_raw_cmd;
3292 cont = &raw_cmd_cont;
3293 ret = wait_til_done(floppy_start, 1);
3294#ifdef DCL_DEBUG
Joe Perchesa81ee5442010-03-10 15:20:46 -08003295 if (DP->flags & FD_DEBUG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296 DPRINT("calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297#endif
3298
3299 if (ret != -EINTR && FDCS->reset)
3300 ret = -EIO;
3301
3302 DRS->track = NO_TRACK;
3303
3304 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3305 if (!ret)
3306 ret = ret2;
3307 raw_cmd_free(&my_raw_cmd);
3308 return ret;
3309}
3310
3311static int invalidate_drive(struct block_device *bdev)
3312{
3313 /* invalidate the buffer track to force a reread */
3314 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3315 process_fd_request();
3316 check_disk_change(bdev);
3317 return 0;
3318}
3319
3320static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
3321 int drive, int type, struct block_device *bdev)
3322{
3323 int cnt;
3324
3325 /* sanity checking for parameters. */
3326 if (g->sect <= 0 ||
3327 g->head <= 0 ||
3328 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3329 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003330 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 return -EINVAL;
3332 if (type) {
3333 if (!capable(CAP_SYS_ADMIN))
3334 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003335 mutex_lock(&open_lock);
Jiri Slaby8516a502009-06-30 11:41:44 -07003336 if (lock_fdc(drive, 1)) {
3337 mutex_unlock(&open_lock);
3338 return -EINTR;
3339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 floppy_type[type] = *g;
3341 floppy_type[type].name = "user format";
3342 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3343 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3344 floppy_type[type].size + 1;
3345 process_fd_request();
3346 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3347 struct block_device *bdev = opened_bdev[cnt];
3348 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3349 continue;
Christoph Hellwig2ef41632005-05-05 16:15:59 -07003350 __invalidate_device(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003352 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 } else {
3354 int oldStretch;
3355 LOCK_FDC(drive, 1);
3356 if (cmd != FDDEFPRM)
3357 /* notice a disk change immediately, else
3358 * we lose our settings immediately*/
3359 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3360 oldStretch = g->stretch;
3361 user_params[drive] = *g;
3362 if (buffer_drive == drive)
3363 SUPBOUND(buffer_max, user_params[drive].sect);
3364 current_type[drive] = &user_params[drive];
3365 floppy_sizes[drive] = user_params[drive].size;
3366 if (cmd == FDDEFPRM)
3367 DRS->keep_data = -1;
3368 else
3369 DRS->keep_data = 1;
3370 /* invalidation. Invalidate only when needed, i.e.
3371 * when there are already sectors in the buffer cache
3372 * whose number will change. This is useful, because
3373 * mtools often changes the geometry of the disk after
3374 * looking at the boot block */
3375 if (DRS->maxblock > user_params[drive].sect ||
3376 DRS->maxtrack ||
3377 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003378 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 invalidate_drive(bdev);
3380 else
3381 process_fd_request();
3382 }
3383 return 0;
3384}
3385
3386/* handle obsolete ioctl's */
3387static int ioctl_table[] = {
3388 FDCLRPRM,
3389 FDSETPRM,
3390 FDDEFPRM,
3391 FDGETPRM,
3392 FDMSGON,
3393 FDMSGOFF,
3394 FDFMTBEG,
3395 FDFMTTRK,
3396 FDFMTEND,
3397 FDSETEMSGTRESH,
3398 FDFLUSH,
3399 FDSETMAXERRS,
3400 FDGETMAXERRS,
3401 FDGETDRVTYP,
3402 FDSETDRVPRM,
3403 FDGETDRVPRM,
3404 FDGETDRVSTAT,
3405 FDPOLLDRVSTAT,
3406 FDRESET,
3407 FDGETFDCSTAT,
3408 FDWERRORCLR,
3409 FDWERRORGET,
3410 FDRAWCMD,
3411 FDEJECT,
3412 FDTWADDLE
3413};
3414
3415static inline int normalize_ioctl(int *cmd, int *size)
3416{
3417 int i;
3418
3419 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3420 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3421 *size = _IOC_SIZE(*cmd);
3422 *cmd = ioctl_table[i];
3423 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003424 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 return -EFAULT;
3426 }
3427 return 0;
3428 }
3429 }
3430 return -EINVAL;
3431}
3432
3433static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3434{
3435 if (type)
3436 *g = &floppy_type[type];
3437 else {
3438 LOCK_FDC(drive, 0);
3439 CALL(poll_drive(0, 0));
3440 process_fd_request();
3441 *g = current_type[drive];
3442 }
3443 if (!*g)
3444 return -ENODEV;
3445 return 0;
3446}
3447
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003448static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3449{
3450 int drive = (long)bdev->bd_disk->private_data;
3451 int type = ITYPE(drive_state[drive].fd_device);
3452 struct floppy_struct *g;
3453 int ret;
3454
3455 ret = get_floppy_geometry(drive, type, &g);
3456 if (ret)
3457 return ret;
3458
3459 geo->heads = g->head;
3460 geo->sectors = g->sect;
3461 geo->cylinders = g->track;
3462 return 0;
3463}
3464
Al Viroa4af9b42008-03-02 09:27:55 -05003465static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 unsigned long param)
3467{
Al Viroa4af9b42008-03-02 09:27:55 -05003468#define FD_IOCTL_ALLOWED (mode & (FMODE_WRITE|FMODE_WRITE_IOCTL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469#define OUT(c,x) case c: outparam = (const char *) (x); break
3470#define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0
3471
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 Perchesa81ee5442010-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 Perchesa81ee5442010-03-10 15:20:46 -08003495 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 return -EINVAL;
3497
Joe Perchesa81ee5442010-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)
3512 ECALL(fd_copyin((void __user *)param, &inparam, size))
3513
3514 switch (cmd) {
3515 case FDEJECT:
3516 if (UDRS->fd_ref != 1)
3517 /* somebody else has this drive open */
3518 return -EBUSY;
3519 LOCK_FDC(drive, 1);
3520
3521 /* do the actual eject. Fails on
3522 * non-Sparc architectures */
3523 ret = fd_eject(UNIT(drive));
3524
3525 USETF(FD_DISK_CHANGED);
3526 USETF(FD_VERIFY);
3527 process_fd_request();
3528 return ret;
3529 case FDCLRPRM:
3530 LOCK_FDC(drive, 1);
3531 current_type[drive] = NULL;
3532 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3533 UDRS->keep_data = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003534 return invalidate_drive(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 case FDSETPRM:
3536 case FDDEFPRM:
3537 return set_geometry(cmd, &inparam.g,
Al Viroa4af9b42008-03-02 09:27:55 -05003538 drive, type, bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539 case FDGETPRM:
3540 ECALL(get_floppy_geometry(drive, type,
3541 (struct floppy_struct **)
3542 &outparam));
3543 break;
3544
3545 case FDMSGON:
3546 UDP->flags |= FTD_MSG;
3547 return 0;
3548 case FDMSGOFF:
3549 UDP->flags &= ~FTD_MSG;
3550 return 0;
3551
3552 case FDFMTBEG:
3553 LOCK_FDC(drive, 1);
3554 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:
3568 LOCK_FDC(drive, 1);
Al Viroa4af9b42008-03-02 09:27:55 -05003569 return invalidate_drive(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570
3571 case FDSETEMSGTRESH:
3572 UDP->max_errors.reporting =
3573 (unsigned short)(param & 0x0f);
3574 return 0;
3575 OUT(FDGETMAXERRS, &UDP->max_errors);
3576 IN(FDSETMAXERRS, &UDP->max_errors, max_errors);
3577
3578 case FDGETDRVTYP:
3579 outparam = drive_name(type, drive);
3580 SUPBOUND(size, strlen(outparam) + 1);
3581 break;
3582
3583 IN(FDSETDRVPRM, UDP, dp);
3584 OUT(FDGETDRVPRM, UDP);
3585
3586 case FDPOLLDRVSTAT:
3587 LOCK_FDC(drive, 1);
3588 CALL(poll_drive(1, FD_RAW_NEED_DISK));
3589 process_fd_request();
3590 /* fall through */
3591 OUT(FDGETDRVSTAT, UDRS);
3592
3593 case FDRESET:
3594 return user_reset_fdc(drive, (int)param, 1);
3595
3596 OUT(FDGETFDCSTAT, UFDCS);
3597
3598 case FDWERRORCLR:
Joe Perchesb87c9e02010-03-10 15:20:50 -08003599 memset(UDRWE, 0, sizeof(*UDRWE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 return 0;
3601 OUT(FDWERRORGET, UDRWE);
3602
3603 case FDRAWCMD:
3604 if (type)
3605 return -EINVAL;
3606 LOCK_FDC(drive, 1);
3607 set_floppy(drive);
3608 CALL(i = raw_cmd_ioctl(cmd, (void __user *)param));
3609 process_fd_request();
3610 return i;
3611
3612 case FDTWADDLE:
3613 LOCK_FDC(drive, 1);
3614 twaddle();
3615 process_fd_request();
3616 return 0;
3617
3618 default:
3619 return -EINVAL;
3620 }
3621
3622 if (_IOC_DIR(cmd) & _IOC_READ)
3623 return fd_copyout((void __user *)param, outparam, size);
3624 else
3625 return 0;
3626#undef OUT
3627#undef IN
3628}
3629
3630static void __init config_types(void)
3631{
Joe Perchesb46df352010-03-10 15:20:46 -08003632 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 int drive;
3634
3635 /* read drive info out of physical CMOS */
3636 drive = 0;
3637 if (!UDP->cmos)
3638 UDP->cmos = FLOPPY0_TYPE;
3639 drive = 1;
3640 if (!UDP->cmos && FLOPPY1_TYPE)
3641 UDP->cmos = FLOPPY1_TYPE;
3642
Jesper Juhl06f748c2007-10-16 23:30:57 -07003643 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644
3645 for (drive = 0; drive < N_DRIVE; drive++) {
3646 unsigned int type = UDP->cmos;
3647 struct floppy_drive_params *params;
3648 const char *name = NULL;
3649 static char temparea[32];
3650
Tobias Klauser945f3902006-01-08 01:05:11 -08003651 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 params = &default_drive_params[type].params;
3653 if (type) {
3654 name = default_drive_params[type].name;
3655 allowed_drive_mask |= 1 << drive;
3656 } else
3657 allowed_drive_mask &= ~(1 << drive);
3658 } else {
3659 params = &default_drive_params[0].params;
3660 sprintf(temparea, "unknown type %d (usb?)", type);
3661 name = temparea;
3662 }
3663 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003664 const char *prepend;
3665 if (!has_drive) {
3666 prepend = "";
3667 has_drive = true;
3668 pr_info("Floppy drive(s):");
3669 } else {
3670 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671 }
Joe Perchesb46df352010-03-10 15:20:46 -08003672
3673 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674 }
3675 *UDP = *params;
3676 }
Joe Perchesb46df352010-03-10 15:20:46 -08003677
3678 if (has_drive)
3679 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680}
3681
Al Viroa4af9b42008-03-02 09:27:55 -05003682static int floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683{
Al Viroa4af9b42008-03-02 09:27:55 -05003684 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003686 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 if (UDRS->fd_ref < 0)
3688 UDRS->fd_ref = 0;
3689 else if (!UDRS->fd_ref--) {
3690 DPRINT("floppy_release with fd_ref == 0");
3691 UDRS->fd_ref = 0;
3692 }
3693 if (!UDRS->fd_ref)
3694 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003695 mutex_unlock(&open_lock);
Ingo Molnar3e541a4a2006-07-03 00:24:23 -07003696
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697 return 0;
3698}
3699
3700/*
3701 * floppy_open check for aliasing (/dev/fd0 can be the same as
3702 * /dev/PS0 etc), and disallows simultaneous access to the same
3703 * drive with different device numbers.
3704 */
Al Viroa4af9b42008-03-02 09:27:55 -05003705static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706{
Al Viroa4af9b42008-03-02 09:27:55 -05003707 int drive = (long)bdev->bd_disk->private_data;
3708 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 int try;
3710 int res = -EBUSY;
3711 char *tmp;
3712
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003713 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003715 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716 goto out2;
3717
3718 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
3719 USETF(FD_DISK_CHANGED);
3720 USETF(FD_VERIFY);
3721 }
3722
Al Viroa4af9b42008-03-02 09:27:55 -05003723 if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724 goto out2;
3725
Al Viroa4af9b42008-03-02 09:27:55 -05003726 if (mode & FMODE_EXCL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727 UDRS->fd_ref = -1;
3728 else
3729 UDRS->fd_ref++;
3730
Al Viroa4af9b42008-03-02 09:27:55 -05003731 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732
3733 res = -ENXIO;
3734
3735 if (!floppy_track_buffer) {
3736 /* if opening an ED drive, reserve a big buffer,
3737 * else reserve a small one */
3738 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3739 try = 64; /* Only 48 actually useful */
3740 else
3741 try = 32; /* Only 24 actually useful */
3742
3743 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3744 if (!tmp && !floppy_track_buffer) {
3745 try >>= 1; /* buffer only one side */
3746 INFBOUND(try, 16);
3747 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3748 }
Joe Perchesa81ee5442010-03-10 15:20:46 -08003749 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751 if (!tmp && !floppy_track_buffer) {
3752 DPRINT("Unable to allocate DMA memory\n");
3753 goto out;
3754 }
3755 if (floppy_track_buffer) {
3756 if (tmp)
3757 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3758 } else {
3759 buffer_min = buffer_max = -1;
3760 floppy_track_buffer = tmp;
3761 max_buffer_sectors = try;
3762 }
3763 }
3764
Al Viroa4af9b42008-03-02 09:27:55 -05003765 new_dev = MINOR(bdev->bd_dev);
3766 UDRS->fd_device = new_dev;
3767 set_capacity(disks[drive], floppy_sizes[new_dev]);
3768 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769 if (buffer_drive == drive)
3770 buffer_track = -1;
3771 }
3772
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773 if (UFDCS->rawcmd == 1)
3774 UFDCS->rawcmd = 2;
3775
Al Viroa4af9b42008-03-02 09:27:55 -05003776 if (!(mode & FMODE_NDELAY)) {
3777 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778 UDRS->last_checked = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003779 check_disk_change(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780 if (UTESTF(FD_DISK_CHANGED))
3781 goto out;
3782 }
3783 res = -EROFS;
Al Viroa4af9b42008-03-02 09:27:55 -05003784 if ((mode & FMODE_WRITE) && !(UTESTF(FD_DISK_WRITABLE)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 goto out;
3786 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003787 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788 return 0;
3789out:
3790 if (UDRS->fd_ref < 0)
3791 UDRS->fd_ref = 0;
3792 else
3793 UDRS->fd_ref--;
3794 if (!UDRS->fd_ref)
3795 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003797 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798 return res;
3799}
3800
3801/*
3802 * Check if the disk has been changed or if a change has been faked.
3803 */
3804static int check_floppy_change(struct gendisk *disk)
3805{
3806 int drive = (long)disk->private_data;
3807
3808 if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY))
3809 return 1;
3810
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003811 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812 lock_fdc(drive, 0);
3813 poll_drive(0, 0);
3814 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815 }
3816
3817 if (UTESTF(FD_DISK_CHANGED) ||
3818 UTESTF(FD_VERIFY) ||
3819 test_bit(drive, &fake_change) ||
3820 (!ITYPE(UDRS->fd_device) && !current_type[drive]))
3821 return 1;
3822 return 0;
3823}
3824
3825/*
3826 * This implements "read block 0" for floppy_revalidate().
3827 * Needed for format autodetection, checking whether there is
3828 * a disk in the drive, and whether that disk is writable.
3829 */
3830
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003831static void floppy_rb0_complete(struct bio *bio, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833 complete((struct completion *)bio->bi_private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834}
3835
3836static int __floppy_read_block_0(struct block_device *bdev)
3837{
3838 struct bio bio;
3839 struct bio_vec bio_vec;
3840 struct completion complete;
3841 struct page *page;
3842 size_t size;
3843
3844 page = alloc_page(GFP_NOIO);
3845 if (!page) {
3846 process_fd_request();
3847 return -ENOMEM;
3848 }
3849
3850 size = bdev->bd_block_size;
3851 if (!size)
3852 size = 1024;
3853
3854 bio_init(&bio);
3855 bio.bi_io_vec = &bio_vec;
3856 bio_vec.bv_page = page;
3857 bio_vec.bv_len = size;
3858 bio_vec.bv_offset = 0;
3859 bio.bi_vcnt = 1;
3860 bio.bi_idx = 0;
3861 bio.bi_size = size;
3862 bio.bi_bdev = bdev;
3863 bio.bi_sector = 0;
3864 init_completion(&complete);
3865 bio.bi_private = &complete;
3866 bio.bi_end_io = floppy_rb0_complete;
3867
3868 submit_bio(READ, &bio);
3869 generic_unplug_device(bdev_get_queue(bdev));
3870 process_fd_request();
3871 wait_for_completion(&complete);
3872
3873 __free_page(page);
3874
3875 return 0;
3876}
3877
3878/* revalidate the floppy disk, i.e. trigger format autodetection by reading
3879 * the bootblock (block 0). "Autodetection" is also needed to check whether
3880 * there is a disk in the drive at all... Thus we also do it for fixed
3881 * geometry formats */
3882static int floppy_revalidate(struct gendisk *disk)
3883{
3884 int drive = (long)disk->private_data;
3885#define NO_GEOM (!current_type[drive] && !ITYPE(UDRS->fd_device))
3886 int cf;
3887 int res = 0;
3888
3889 if (UTESTF(FD_DISK_CHANGED) ||
3890 UTESTF(FD_VERIFY) || test_bit(drive, &fake_change) || NO_GEOM) {
3891 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08003892 pr_info("VFS: revalidate called on non-open device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 return -EFAULT;
3894 }
3895 lock_fdc(drive, 0);
3896 cf = UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY);
3897 if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)) {
3898 process_fd_request(); /*already done by another thread */
3899 return 0;
3900 }
3901 UDRS->maxblock = 0;
3902 UDRS->maxtrack = 0;
3903 if (buffer_drive == drive)
3904 buffer_track = -1;
3905 clear_bit(drive, &fake_change);
3906 UCLEARF(FD_DISK_CHANGED);
3907 if (cf)
3908 UDRS->generation++;
3909 if (NO_GEOM) {
3910 /* auto-sensing */
3911 res = __floppy_read_block_0(opened_bdev[drive]);
3912 } else {
3913 if (cf)
3914 poll_drive(0, FD_RAW_NEED_DISK);
3915 process_fd_request();
3916 }
3917 }
3918 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
3919 return res;
3920}
3921
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07003922static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07003923 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05003924 .open = floppy_open,
3925 .release = floppy_release,
3926 .locked_ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003927 .getgeo = fd_getgeo,
3928 .media_changed = check_floppy_change,
3929 .revalidate_disk = floppy_revalidate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932/*
3933 * Floppy Driver initialization
3934 * =============================
3935 */
3936
3937/* Determine the floppy disk controller type */
3938/* This routine was written by David C. Niemi */
3939static char __init get_fdc_version(void)
3940{
3941 int r;
3942
3943 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
3944 if (FDCS->reset)
3945 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003946 r = result();
3947 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948 return FDC_NONE; /* No FDC present ??? */
3949 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003950 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003951 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3952 }
3953 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003954 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3955 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 return FDC_UNKNOWN;
3957 }
3958
3959 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003960 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3962 }
3963
3964 output_byte(FD_PERPENDICULAR);
3965 if (need_more_output() == MORE_OUTPUT) {
3966 output_byte(0);
3967 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003968 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969 return FDC_82072A; /* 82072A as found on Sparcs. */
3970 }
3971
3972 output_byte(FD_UNLOCK);
3973 r = result();
3974 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003975 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003976 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 * LOCK/UNLOCK */
3978 }
3979 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003980 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3981 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982 return FDC_UNKNOWN;
3983 }
3984 output_byte(FD_PARTID);
3985 r = result();
3986 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003987 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3988 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 return FDC_UNKNOWN;
3990 }
3991 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003992 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 return FDC_82077; /* Revised 82077AA passes all the tests */
3994 }
3995 switch (reply_buffer[0] >> 5) {
3996 case 0x0:
3997 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08003998 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 return FDC_82078;
4000 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08004001 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002 return FDC_82078;
4003 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08004004 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 return FDC_S82078B;
4006 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08004007 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 return FDC_87306;
4009 default:
Joe Perchesb46df352010-03-10 15:20:46 -08004010 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
4011 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012 return FDC_82078_UNKN;
4013 }
4014} /* get_fdc_version */
4015
4016/* lilo configuration */
4017
4018static void __init floppy_set_flags(int *ints, int param, int param2)
4019{
4020 int i;
4021
4022 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4023 if (param)
4024 default_drive_params[i].params.flags |= param2;
4025 else
4026 default_drive_params[i].params.flags &= ~param2;
4027 }
4028 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
4029}
4030
4031static void __init daring(int *ints, int param, int param2)
4032{
4033 int i;
4034
4035 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4036 if (param) {
4037 default_drive_params[i].params.select_delay = 0;
4038 default_drive_params[i].params.flags |=
4039 FD_SILENT_DCL_CLEAR;
4040 } else {
4041 default_drive_params[i].params.select_delay =
4042 2 * HZ / 100;
4043 default_drive_params[i].params.flags &=
4044 ~FD_SILENT_DCL_CLEAR;
4045 }
4046 }
4047 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
4048}
4049
4050static void __init set_cmos(int *ints, int dummy, int dummy2)
4051{
4052 int current_drive = 0;
4053
4054 if (ints[0] != 2) {
4055 DPRINT("wrong number of parameters for CMOS\n");
4056 return;
4057 }
4058 current_drive = ints[1];
4059 if (current_drive < 0 || current_drive >= 8) {
4060 DPRINT("bad drive for set_cmos\n");
4061 return;
4062 }
4063#if N_FDC > 1
4064 if (current_drive >= 4 && !FDC2)
4065 FDC2 = 0x370;
4066#endif
4067 DP->cmos = ints[2];
4068 DPRINT("setting CMOS code to %d\n", ints[2]);
4069}
4070
4071static struct param_table {
4072 const char *name;
4073 void (*fn) (int *ints, int param, int param2);
4074 int *var;
4075 int def_param;
4076 int param2;
4077} config_params[] __initdata = {
4078 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4079 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4080 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4081 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4082 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4083 {"daring", daring, NULL, 1, 0},
4084#if N_FDC > 1
4085 {"two_fdc", NULL, &FDC2, 0x370, 0},
4086 {"one_fdc", NULL, &FDC2, 0, 0},
4087#endif
4088 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4089 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4090 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4091 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4092 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4093 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4094 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4095 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4096 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4097 {"nofifo", NULL, &no_fifo, 0x20, 0},
4098 {"usefifo", NULL, &no_fifo, 0, 0},
4099 {"cmos", set_cmos, NULL, 0, 0},
4100 {"slow", NULL, &slow_floppy, 1, 0},
4101 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4102 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4103 {"L40SX", NULL, &print_unex, 0, 0}
4104
4105 EXTRA_FLOPPY_PARAMS
4106};
4107
4108static int __init floppy_setup(char *str)
4109{
4110 int i;
4111 int param;
4112 int ints[11];
4113
4114 str = get_options(str, ARRAY_SIZE(ints), ints);
4115 if (str) {
4116 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4117 if (strcmp(str, config_params[i].name) == 0) {
4118 if (ints[0])
4119 param = ints[1];
4120 else
4121 param = config_params[i].def_param;
4122 if (config_params[i].fn)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004123 config_params[i].fn(ints, param,
4124 config_params[i].
4125 param2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126 if (config_params[i].var) {
4127 DPRINT("%s=%d\n", str, param);
4128 *config_params[i].var = param;
4129 }
4130 return 1;
4131 }
4132 }
4133 }
4134 if (str) {
4135 DPRINT("unknown floppy option [%s]\n", str);
4136
4137 DPRINT("allowed options are:");
4138 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004139 pr_cont(" %s", config_params[i].name);
4140 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141 } else
4142 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004143 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144 return 0;
4145}
4146
4147static int have_no_fdc = -ENODEV;
4148
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004149static ssize_t floppy_cmos_show(struct device *dev,
4150 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004151{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004152 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004153 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004154
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004155 drive = p->id;
4156 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004157}
Joe Perches48c8cee2010-03-10 15:20:45 -08004158
4159DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004160
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161static void floppy_device_release(struct device *dev)
4162{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163}
4164
Frans Popc90cd332009-07-25 22:24:54 +02004165static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004166{
4167 int fdc;
4168
4169 for (fdc = 0; fdc < N_FDC; fdc++)
4170 if (FDCS->address != -1)
4171 user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
4172
4173 return 0;
4174}
4175
Alexey Dobriyan47145212009-12-14 18:00:08 -08004176static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004177 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004178 .restore = floppy_resume,
4179};
4180
4181static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004182 .driver = {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004183 .name = "floppy",
4184 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004185 },
4186};
4187
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004188static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189
4190static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4191{
4192 int drive = (*part & 3) | ((*part & 0x80) >> 5);
4193 if (drive >= N_DRIVE ||
4194 !(allowed_drive_mask & (1 << drive)) ||
4195 fdc_state[FDC(drive)].version == FDC_NONE)
4196 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004197 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198 return NULL;
4199 *part = 0;
4200 return get_disk(disks[drive]);
4201}
4202
4203static int __init floppy_init(void)
4204{
4205 int i, unit, drive;
4206 int err, dr;
4207
Kumar Gala68e1ee62008-09-22 14:41:31 -07004208#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004209 if (check_legacy_ioport(FDC1))
4210 return -ENODEV;
4211#endif
4212
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 raw_cmd = NULL;
4214
4215 for (dr = 0; dr < N_DRIVE; dr++) {
4216 disks[dr] = alloc_disk(1);
4217 if (!disks[dr]) {
4218 err = -ENOMEM;
4219 goto out_put_disk;
4220 }
4221
4222 disks[dr]->major = FLOPPY_MAJOR;
4223 disks[dr]->first_minor = TOMINOR(dr);
4224 disks[dr]->fops = &floppy_fops;
4225 sprintf(disks[dr]->disk_name, "fd%d", dr);
4226
4227 init_timer(&motor_off_timer[dr]);
4228 motor_off_timer[dr].data = dr;
4229 motor_off_timer[dr].function = motor_off_callback;
4230 }
4231
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232 err = register_blkdev(FLOPPY_MAJOR, "fd");
4233 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004234 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004236 err = platform_driver_register(&floppy_driver);
4237 if (err)
4238 goto out_unreg_blkdev;
4239
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
4241 if (!floppy_queue) {
4242 err = -ENOMEM;
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004243 goto out_unreg_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244 }
Martin K. Petersen086fa5f2010-02-26 00:20:38 -05004245 blk_queue_max_hw_sectors(floppy_queue, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246
4247 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4248 floppy_find, NULL, NULL);
4249
4250 for (i = 0; i < 256; i++)
4251 if (ITYPE(i))
4252 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4253 else
4254 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4255
4256 reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT);
4257 config_types();
4258
4259 for (i = 0; i < N_FDC; i++) {
4260 fdc = i;
Joe Perchesb87c9e02010-03-10 15:20:50 -08004261 memset(FDCS, 0, sizeof(*FDCS));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262 FDCS->dtr = -1;
4263 FDCS->dor = 0x4;
4264#if defined(__sparc__) || defined(__mc68000__)
4265 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
4266#ifdef __mc68000__
4267 if (MACH_IS_SUN3X)
4268#endif
4269 FDCS->version = FDC_82072A;
4270#endif
4271 }
4272
4273 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274 fdc_state[0].address = FDC1;
4275 if (fdc_state[0].address == -1) {
4276 del_timer(&fd_timeout);
4277 err = -ENODEV;
4278 goto out_unreg_region;
4279 }
4280#if N_FDC > 1
4281 fdc_state[1].address = FDC2;
4282#endif
4283
4284 fdc = 0; /* reset fdc in case of unexpected interrupt */
4285 err = floppy_grab_irq_and_dma();
4286 if (err) {
4287 del_timer(&fd_timeout);
4288 err = -EBUSY;
4289 goto out_unreg_region;
4290 }
4291
4292 /* initialise drive state */
4293 for (drive = 0; drive < N_DRIVE; drive++) {
Joe Perchesb87c9e02010-03-10 15:20:50 -08004294 memset(UDRS, 0, sizeof(*UDRS));
4295 memset(UDRWE, 0, sizeof(*UDRWE));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296 USETF(FD_DISK_NEWCHANGE);
4297 USETF(FD_DISK_CHANGED);
4298 USETF(FD_VERIFY);
4299 UDRS->fd_device = -1;
4300 floppy_track_buffer = NULL;
4301 max_buffer_sectors = 0;
4302 }
4303 /*
4304 * Small 10 msec delay to let through any interrupt that
4305 * initialization might have triggered, to not
4306 * confuse detection:
4307 */
4308 msleep(10);
4309
4310 for (i = 0; i < N_FDC; i++) {
4311 fdc = i;
4312 FDCS->driver_version = FD_DRIVER_VERSION;
4313 for (unit = 0; unit < 4; unit++)
4314 FDCS->track[unit] = 0;
4315 if (FDCS->address == -1)
4316 continue;
4317 FDCS->rawcmd = 2;
4318 if (user_reset_fdc(-1, FD_RESET_ALWAYS, 0)) {
4319 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004320 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321 FDCS->address = -1;
4322 FDCS->version = FDC_NONE;
4323 continue;
4324 }
4325 /* Try to determine the floppy controller type */
4326 FDCS->version = get_fdc_version();
4327 if (FDCS->version == FDC_NONE) {
4328 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004329 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 FDCS->address = -1;
4331 continue;
4332 }
4333 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4334 can_use_virtual_dma = 0;
4335
4336 have_no_fdc = 0;
4337 /* Not all FDCs seem to be able to handle the version command
4338 * properly, so force a reset for the standard FDC clones,
4339 * to avoid interrupt garbage.
4340 */
4341 user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
4342 }
4343 fdc = 0;
4344 del_timer(&fd_timeout);
4345 current_drive = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346 initialising = 0;
4347 if (have_no_fdc) {
4348 DPRINT("no floppy controllers found\n");
4349 err = have_no_fdc;
4350 goto out_flush_work;
4351 }
4352
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353 for (drive = 0; drive < N_DRIVE; drive++) {
4354 if (!(allowed_drive_mask & (1 << drive)))
4355 continue;
4356 if (fdc_state[FDC(drive)].version == FDC_NONE)
4357 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004358
4359 floppy_device[drive].name = floppy_device_name;
4360 floppy_device[drive].id = drive;
4361 floppy_device[drive].dev.release = floppy_device_release;
4362
4363 err = platform_device_register(&floppy_device[drive]);
4364 if (err)
4365 goto out_flush_work;
4366
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004367 err = device_create_file(&floppy_device[drive].dev,
4368 &dev_attr_cmos);
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004369 if (err)
4370 goto out_unreg_platform_dev;
4371
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372 /* to be cleaned up... */
4373 disks[drive]->private_data = (void *)(long)drive;
4374 disks[drive]->queue = floppy_queue;
4375 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004376 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 add_disk(disks[drive]);
4378 }
4379
4380 return 0;
4381
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004382out_unreg_platform_dev:
4383 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384out_flush_work:
4385 flush_scheduled_work();
4386 if (usage_count)
4387 floppy_release_irq_and_dma();
4388out_unreg_region:
4389 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4390 blk_cleanup_queue(floppy_queue);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004391out_unreg_driver:
4392 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393out_unreg_blkdev:
4394 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395out_put_disk:
4396 while (dr--) {
4397 del_timer(&motor_off_timer[dr]);
4398 put_disk(disks[dr]);
4399 }
4400 return err;
4401}
4402
4403static DEFINE_SPINLOCK(floppy_usage_lock);
4404
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004405static const struct io_region {
4406 int offset;
4407 int size;
4408} io_regions[] = {
4409 { 2, 1 },
4410 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4411 { 4, 2 },
4412 /* address + 6 is reserved, and may be taken by IDE.
4413 * Unfortunately, Adaptec doesn't know this :-(, */
4414 { 7, 1 },
4415};
4416
4417static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4418{
4419 while (p != io_regions) {
4420 p--;
4421 release_region(FDCS->address + p->offset, p->size);
4422 }
4423}
4424
4425#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4426
4427static int floppy_request_regions(int fdc)
4428{
4429 const struct io_region *p;
4430
4431 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004432 if (!request_region(FDCS->address + p->offset,
4433 p->size, "floppy")) {
4434 DPRINT("Floppy io-port 0x%04lx in use\n",
4435 FDCS->address + p->offset);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004436 floppy_release_allocated_regions(fdc, p);
4437 return -EBUSY;
4438 }
4439 }
4440 return 0;
4441}
4442
4443static void floppy_release_regions(int fdc)
4444{
4445 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4446}
4447
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448static int floppy_grab_irq_and_dma(void)
4449{
4450 unsigned long flags;
4451
4452 spin_lock_irqsave(&floppy_usage_lock, flags);
4453 if (usage_count++) {
4454 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4455 return 0;
4456 }
4457 spin_unlock_irqrestore(&floppy_usage_lock, flags);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004458
4459 /*
4460 * We might have scheduled a free_irq(), wait it to
4461 * drain first:
4462 */
4463 flush_scheduled_work();
4464
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465 if (fd_request_irq()) {
4466 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4467 FLOPPY_IRQ);
4468 spin_lock_irqsave(&floppy_usage_lock, flags);
4469 usage_count--;
4470 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4471 return -1;
4472 }
4473 if (fd_request_dma()) {
4474 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4475 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004476 if (can_use_virtual_dma & 2)
4477 use_virtual_dma = can_use_virtual_dma = 1;
4478 if (!(can_use_virtual_dma & 1)) {
4479 fd_free_irq();
4480 spin_lock_irqsave(&floppy_usage_lock, flags);
4481 usage_count--;
4482 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4483 return -1;
4484 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 }
4486
4487 for (fdc = 0; fdc < N_FDC; fdc++) {
4488 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004489 if (floppy_request_regions(fdc))
4490 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 }
4492 }
4493 for (fdc = 0; fdc < N_FDC; fdc++) {
4494 if (FDCS->address != -1) {
4495 reset_fdc_info(1);
4496 fd_outb(FDCS->dor, FD_DOR);
4497 }
4498 }
4499 fdc = 0;
4500 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4501
4502 for (fdc = 0; fdc < N_FDC; fdc++)
4503 if (FDCS->address != -1)
4504 fd_outb(FDCS->dor, FD_DOR);
4505 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004506 * The driver will try and free resources and relies on us
4507 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 */
4509 fdc = 0;
4510 irqdma_allocated = 1;
4511 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004512cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513 fd_free_irq();
4514 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004515 while (--fdc >= 0)
4516 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517 spin_lock_irqsave(&floppy_usage_lock, flags);
4518 usage_count--;
4519 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4520 return -1;
4521}
4522
4523static void floppy_release_irq_and_dma(void)
4524{
4525 int old_fdc;
4526#ifdef FLOPPY_SANITY_CHECK
4527#ifndef __sparc__
4528 int drive;
4529#endif
4530#endif
4531 long tmpsize;
4532 unsigned long tmpaddr;
4533 unsigned long flags;
4534
4535 spin_lock_irqsave(&floppy_usage_lock, flags);
4536 if (--usage_count) {
4537 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4538 return;
4539 }
4540 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4541 if (irqdma_allocated) {
4542 fd_disable_dma();
4543 fd_free_dma();
Ingo Molnar3e541a4a2006-07-03 00:24:23 -07004544 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545 irqdma_allocated = 0;
4546 }
4547 set_dor(0, ~0, 8);
4548#if N_FDC > 1
4549 set_dor(1, ~8, 0);
4550#endif
4551 floppy_enable_hlt();
4552
4553 if (floppy_track_buffer && max_buffer_sectors) {
4554 tmpsize = max_buffer_sectors * 1024;
4555 tmpaddr = (unsigned long)floppy_track_buffer;
4556 floppy_track_buffer = NULL;
4557 max_buffer_sectors = 0;
4558 buffer_min = buffer_max = -1;
4559 fd_dma_mem_free(tmpaddr, tmpsize);
4560 }
4561#ifdef FLOPPY_SANITY_CHECK
4562#ifndef __sparc__
4563 for (drive = 0; drive < N_FDC * 4; drive++)
4564 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004565 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566#endif
4567
4568 if (timer_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004569 pr_info("floppy timer still active:%s\n", timeout_message);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004571 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004572 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004573 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574#endif
4575 old_fdc = fdc;
4576 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004577 if (FDCS->address != -1)
4578 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579 fdc = old_fdc;
4580}
4581
4582#ifdef MODULE
4583
4584static char *floppy;
4585
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586static void __init parse_floppy_cfg_string(char *cfg)
4587{
4588 char *ptr;
4589
4590 while (*cfg) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004591 ptr = cfg;
4592 while (*cfg && *cfg != ' ' && *cfg != '\t')
4593 cfg++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594 if (*cfg) {
4595 *cfg = '\0';
4596 cfg++;
4597 }
4598 if (*ptr)
4599 floppy_setup(ptr);
4600 }
4601}
4602
Jon Schindler7afea3b2008-04-29 00:59:21 -07004603static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604{
4605 if (floppy)
4606 parse_floppy_cfg_string(floppy);
4607 return floppy_init();
4608}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004609module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610
Jon Schindler7afea3b2008-04-29 00:59:21 -07004611static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612{
4613 int drive;
4614
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4616 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004617 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618
4619 for (drive = 0; drive < N_DRIVE; drive++) {
4620 del_timer_sync(&motor_off_timer[drive]);
4621
4622 if ((allowed_drive_mask & (1 << drive)) &&
4623 fdc_state[FDC(drive)].version != FDC_NONE) {
4624 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004625 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4626 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627 }
4628 put_disk(disks[drive]);
4629 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004630
4631 del_timer_sync(&fd_timeout);
4632 del_timer_sync(&fd_timer);
4633 blk_cleanup_queue(floppy_queue);
4634
4635 if (usage_count)
4636 floppy_release_irq_and_dma();
4637
4638 /* eject disk, if any */
4639 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640}
Joe Perches48c8cee2010-03-10 15:20:45 -08004641
Jon Schindler7afea3b2008-04-29 00:59:21 -07004642module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643
4644module_param(floppy, charp, 0);
4645module_param(FLOPPY_IRQ, int, 0);
4646module_param(FLOPPY_DMA, int, 0);
4647MODULE_AUTHOR("Alain L. Knaff");
4648MODULE_SUPPORTED_DEVICE("fd");
4649MODULE_LICENSE("GPL");
4650
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004651/* This doesn't actually get used other than for module information */
4652static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004653 {"PNP0700", 0},
4654 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004655};
Joe Perches48c8cee2010-03-10 15:20:45 -08004656
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004657MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4658
Linus Torvalds1da177e2005-04-16 15:20:36 -07004659#else
4660
4661__setup("floppy=", floppy_setup);
4662module_init(floppy_init)
4663#endif
4664
4665MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);