blob: 98de8f4186762680a0ea1ccd2d0cf907c1314b40 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147#undef FLOPPY_SILENT_DCL_CLEAR
148
149#define REALLY_SLOW_IO
150
151#define DEBUGT 2
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152
Joe Perches891eda82010-03-10 15:21:05 -0800153#define DPRINT(format, args...) \
154 pr_info("floppy%d: " format, current_drive, ##args)
155
156#define DCL_DEBUG /* debug disk change line */
Joe Perches87f530d2010-03-10 15:20:54 -0800157#ifdef DCL_DEBUG
158#define debug_dcl(test, fmt, args...) \
159 do { if ((test) & FD_DEBUG) DPRINT(fmt, ##args); } while (0)
160#else
161#define debug_dcl(test, fmt, args...) \
162 do { if (0) DPRINT(fmt, ##args); } while (0)
163#endif
164
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165/* do print messages for unexpected interrupts */
166static int print_unex = 1;
167#include <linux/module.h>
168#include <linux/sched.h>
169#include <linux/fs.h>
170#include <linux/kernel.h>
171#include <linux/timer.h>
172#include <linux/workqueue.h>
173#define FDPATCHES
174#include <linux/fdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175#include <linux/fd.h>
176#include <linux/hdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177#include <linux/errno.h>
178#include <linux/slab.h>
179#include <linux/mm.h>
180#include <linux/bio.h>
181#include <linux/string.h>
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800182#include <linux/jiffies.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183#include <linux/fcntl.h>
184#include <linux/delay.h>
185#include <linux/mc146818rtc.h> /* CMOS defines */
186#include <linux/ioport.h>
187#include <linux/interrupt.h>
188#include <linux/init.h>
Russell Kingd052d1b2005-10-29 19:07:23 +0100189#include <linux/platform_device.h>
Scott James Remnant83f9ef42009-04-02 16:56:47 -0700190#include <linux/mod_devicetable.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191#include <linux/buffer_head.h> /* for invalidate_buffers() */
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800192#include <linux/mutex.h>
Joe Perchesd4937542010-03-10 15:20:44 -0800193#include <linux/io.h>
194#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
196/*
197 * PS/2 floppies have much slower step rates than regular floppies.
198 * It's been recommended that take about 1/4 of the default speed
199 * in some more extreme cases.
200 */
Arnd Bergmann2a48fc02010-06-02 14:28:52 +0200201static DEFINE_MUTEX(floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202static int slow_floppy;
203
204#include <asm/dma.h>
205#include <asm/irq.h>
206#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
208static int FLOPPY_IRQ = 6;
209static int FLOPPY_DMA = 2;
210static int can_use_virtual_dma = 2;
211/* =======
212 * can use virtual DMA:
213 * 0 = use of virtual DMA disallowed by config
214 * 1 = use of virtual DMA prescribed by config
215 * 2 = no virtual DMA preference configured. By default try hard DMA,
216 * but fall back on virtual DMA when not enough memory available
217 */
218
219static int use_virtual_dma;
220/* =======
221 * use virtual DMA
222 * 0 using hard DMA
223 * 1 using virtual DMA
224 * This variable is set to virtual when a DMA mem problem arises, and
225 * reset back in floppy_grab_irq_and_dma.
226 * It is not safe to reset it in other circumstances, because the floppy
227 * driver may have several buffers in use at once, and we do currently not
228 * record each buffers capabilities
229 */
230
231static DEFINE_SPINLOCK(floppy_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
233static unsigned short virtual_dma_port = 0x3f0;
David Howells7d12e782006-10-05 14:55:46 +0100234irqreturn_t floppy_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235static int set_dor(int fdc, char mask, char data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236
237#define K_64 0x10000 /* 64KB */
238
239/* the following is the mask of allowed drives. By default units 2 and
240 * 3 of both floppy controllers are disabled, because switching on the
241 * motor of these drives causes system hangs on some PCI computers. drive
242 * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
243 * a drive is allowed.
244 *
245 * NOTE: This must come before we include the arch floppy header because
246 * some ports reference this variable from there. -DaveM
247 */
248
249static int allowed_drive_mask = 0x33;
250
251#include <asm/floppy.h>
252
253static int irqdma_allocated;
254
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255#include <linux/blkdev.h>
256#include <linux/blkpg.h>
257#include <linux/cdrom.h> /* for the compatibility eject ioctl */
258#include <linux/completion.h>
259
260static struct request *current_req;
Joe Perches48c8cee2010-03-10 15:20:45 -0800261static void do_fd_request(struct request_queue *q);
Jens Axboe48821182010-09-22 09:32:36 +0200262static int set_next_request(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
264#ifndef fd_get_dma_residue
265#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
266#endif
267
268/* Dma Memory related stuff */
269
270#ifndef fd_dma_mem_free
271#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
272#endif
273
274#ifndef fd_dma_mem_alloc
Joe Perches48c8cee2010-03-10 15:20:45 -0800275#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL, get_order(size))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276#endif
277
278static inline void fallback_on_nodma_alloc(char **addr, size_t l)
279{
280#ifdef FLOPPY_CAN_FALLBACK_ON_NODMA
281 if (*addr)
282 return; /* we have the memory */
283 if (can_use_virtual_dma != 2)
284 return; /* no fallback allowed */
Joe Perchesb46df352010-03-10 15:20:46 -0800285 pr_info("DMA memory shortage. Temporarily falling back on virtual DMA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 *addr = (char *)nodma_mem_alloc(l);
287#else
288 return;
289#endif
290}
291
292/* End dma memory related stuff */
293
294static unsigned long fake_change;
Joe Perches29f1c782010-03-10 15:21:00 -0800295static bool initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
Joe Perches48c8cee2010-03-10 15:20:45 -0800297#define ITYPE(x) (((x) >> 2) & 0x1f)
298#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
299#define UNIT(x) ((x) & 0x03) /* drive on fdc */
300#define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700301 /* reverse mapping from unit and fdc to drive */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
Joe Perches48c8cee2010-03-10 15:20:45 -0800304#define DP (&drive_params[current_drive])
305#define DRS (&drive_state[current_drive])
306#define DRWE (&write_errors[current_drive])
307#define FDCS (&fdc_state[fdc])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
Joe Perches48c8cee2010-03-10 15:20:45 -0800309#define UDP (&drive_params[drive])
310#define UDRS (&drive_state[drive])
311#define UDRWE (&write_errors[drive])
312#define UFDCS (&fdc_state[FDC(drive)])
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];
Joe Perches891eda82010-03-10 15:21:05 -0800348static 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;
Jens Axboe48821182010-09-22 09:32:36 +0200416static int fdc_queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417
418/*
419 * This struct defines the different floppy types.
420 *
421 * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
422 * types (e.g. 360kB diskette in 1.2MB drive, etc.). Bit 1 of 'stretch'
423 * tells if the disk is in Commodore 1581 format, which means side 0 sectors
424 * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
425 * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
426 * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
427 * side 0 is on physical side 0 (but with the misnamed sector IDs).
428 * 'stretch' should probably be renamed to something more general, like
Keith Wansbrough9e491842008-09-22 14:57:17 -0700429 * 'options'.
430 *
431 * Bits 2 through 9 of 'stretch' tell the number of the first sector.
432 * The LSB (bit 2) is flipped. For most disks, the first sector
433 * is 1 (represented by 0x00<<2). For some CP/M and music sampler
434 * disks (such as Ensoniq EPS 16plus) it is 0 (represented as 0x01<<2).
435 * For Amstrad CPC disks it is 0xC1 (represented as 0xC0<<2).
436 *
437 * Other parameters should be self-explanatory (see also setfdprm(8)).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 */
439/*
440 Size
441 | Sectors per track
442 | | Head
443 | | | Tracks
444 | | | | Stretch
445 | | | | | Gap 1 size
446 | | | | | | Data rate, | 0x40 for perp
447 | | | | | | | Spec1 (stepping rate, head unload
448 | | | | | | | | /fmt gap (gap2) */
449static struct floppy_struct floppy_type[32] = {
450 { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* 0 no testing */
451 { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360" }, /* 1 360KB PC */
452 { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" }, /* 2 1.2MB AT */
453 { 720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360" }, /* 3 360KB SS 3.5" */
454 { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720" }, /* 4 720KB 3.5" */
455 { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360" }, /* 5 360KB AT */
456 { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" }, /* 6 720KB AT */
457 { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /* 7 1.44MB 3.5" */
458 { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /* 8 2.88MB 3.5" */
459 { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" }, /* 9 3.12MB 3.5" */
460
461 { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */
462 { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */
463 { 820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410" }, /* 12 410KB 5.25" */
464 { 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820" }, /* 13 820KB 3.5" */
465 { 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" }, /* 14 1.48MB 5.25" */
466 { 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" }, /* 15 1.72MB 3.5" */
467 { 840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420" }, /* 16 420KB 5.25" */
468 { 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830" }, /* 17 830KB 3.5" */
469 { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" }, /* 18 1.49MB 5.25" */
470 { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5" */
471
472 { 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880" }, /* 20 880KB 5.25" */
473 { 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5" */
474 { 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5" */
475 { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25" */
476 { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5" */
477 { 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5" */
478 { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5" */
479 { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5" */
480 { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5" */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5" */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700482
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */
484 { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */
485};
486
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487#define SECTSIZE (_FD_SECTSIZE(*floppy))
488
489/* Auto-detection: Disk type used until the next media change occurs. */
490static struct floppy_struct *current_type[N_DRIVE];
491
492/*
493 * User-provided type information. current_type points to
494 * the respective entry of this array.
495 */
496static struct floppy_struct user_params[N_DRIVE];
497
498static sector_t floppy_sizes[256];
499
Hannes Reinecke94fd0db2005-07-15 10:09:25 +0200500static char floppy_device_name[] = "floppy";
501
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502/*
503 * The driver is trying to determine the correct media format
504 * while probing is set. rw_interrupt() clears it after a
505 * successful access.
506 */
507static int probing;
508
509/* Synchronization of FDC access. */
Joe Perches48c8cee2010-03-10 15:20:45 -0800510#define FD_COMMAND_NONE -1
511#define FD_COMMAND_ERROR 2
512#define FD_COMMAND_OKAY 3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
514static volatile int command_status = FD_COMMAND_NONE;
515static unsigned long fdc_busy;
516static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
517static DECLARE_WAIT_QUEUE_HEAD(command_done);
518
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519/* Errors during formatting are counted here. */
520static int format_errors;
521
522/* Format request descriptor. */
523static struct format_descr format_req;
524
525/*
526 * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
527 * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
528 * H is head unload time (1=16ms, 2=32ms, etc)
529 */
530
531/*
532 * Track buffer
533 * Because these are written to by the DMA controller, they must
534 * not contain a 64k byte boundary crossing, or data will be
535 * corrupted/lost.
536 */
537static char *floppy_track_buffer;
538static int max_buffer_sectors;
539
540static int *errors;
Jesper Juhl06f748c2007-10-16 23:30:57 -0700541typedef void (*done_f)(int);
Stephen Hemminger3b06c212010-07-20 20:09:00 -0600542static const struct cont_t {
Joe Perches48c8cee2010-03-10 15:20:45 -0800543 void (*interrupt)(void);
544 /* this is called after the interrupt of the
545 * main command */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700546 void (*redo)(void); /* this is called to retry the operation */
547 void (*error)(void); /* this is called to tally an error */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 done_f done; /* this is called to say if the operation has
549 * succeeded/failed */
550} *cont;
551
552static void floppy_ready(void);
553static void floppy_start(void);
554static void process_fd_request(void);
555static void recalibrate_floppy(void);
556static void floppy_shutdown(unsigned long);
557
Philippe De Muyter5a74db02009-02-18 14:48:36 -0800558static int floppy_request_regions(int);
559static void floppy_release_regions(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560static int floppy_grab_irq_and_dma(void);
561static void floppy_release_irq_and_dma(void);
562
563/*
564 * The "reset" variable should be tested whenever an interrupt is scheduled,
565 * after the commands have been sent. This is to ensure that the driver doesn't
566 * get wedged when the interrupt doesn't come because of a failed command.
567 * reset doesn't need to be tested before sending commands, because
568 * output_byte is automatically disabled when reset is set.
569 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570static void reset_fdc(void);
571
572/*
573 * These are global variables, as that's the easiest way to give
574 * information to interrupts. They are the data used for the current
575 * request.
576 */
Joe Perches48c8cee2010-03-10 15:20:45 -0800577#define NO_TRACK -1
578#define NEED_1_RECAL -2
579#define NEED_2_RECAL -3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
Stephen Hemminger575cfc62010-06-15 13:21:11 +0200581static atomic_t usage_count = ATOMIC_INIT(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582
583/* buffer related variables */
584static int buffer_track = -1;
585static int buffer_drive = -1;
586static int buffer_min = -1;
587static int buffer_max = -1;
588
589/* fdc related variables, should end up in a struct */
590static struct floppy_fdc_state fdc_state[N_FDC];
591static int fdc; /* current fdc */
592
593static struct floppy_struct *_floppy = floppy_type;
594static unsigned char current_drive;
595static long current_count_sectors;
596static unsigned char fsector_t; /* sector in track */
597static unsigned char in_sector_offset; /* offset within physical sector,
598 * expressed in units of 512 bytes */
599
Pekka Enberg2b51dca2010-11-08 14:44:34 +0100600static inline bool drive_no_geom(int drive)
601{
602 return !current_type[drive] && !ITYPE(UDRS->fd_device);
603}
604
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605#ifndef fd_eject
606static inline int fd_eject(int drive)
607{
608 return -EINVAL;
609}
610#endif
611
612/*
613 * Debugging
614 * =========
615 */
616#ifdef DEBUGT
617static long unsigned debugtimer;
618
619static inline void set_debugt(void)
620{
621 debugtimer = jiffies;
622}
623
Joe Perchesded28632010-03-10 15:21:09 -0800624static inline void debugt(const char *func, const char *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625{
626 if (DP->flags & DEBUGT)
Joe Perchesded28632010-03-10 15:21:09 -0800627 pr_info("%s:%s dtime=%lu\n", func, msg, jiffies - debugtimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628}
629#else
630static inline void set_debugt(void) { }
Joe Perchesded28632010-03-10 15:21:09 -0800631static inline void debugt(const char *func, const char *msg) { }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632#endif /* DEBUGT */
633
Joe Perchesa0a52d62010-03-10 15:20:52 -0800634typedef void (*timeout_fn)(unsigned long);
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700635static DEFINE_TIMER(fd_timeout, floppy_shutdown, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
637static const char *timeout_message;
638
Joe Perches275176b2010-03-10 15:21:06 -0800639static void is_alive(const char *func, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640{
641 /* this routine checks whether the floppy driver is "alive" */
Joe Perchesc5297302010-03-10 15:20:58 -0800642 if (test_bit(0, &fdc_busy) && command_status < 2 &&
643 !timer_pending(&fd_timeout)) {
Joe Perches275176b2010-03-10 15:21:06 -0800644 DPRINT("%s: timeout handler died. %s\n", func, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 }
646}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
Joe Perches48c8cee2010-03-10 15:20:45 -0800648static void (*do_floppy)(void) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650#define OLOGSIZE 20
651
Joe Perches48c8cee2010-03-10 15:20:45 -0800652static void (*lasthandler)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653static unsigned long interruptjiffies;
654static unsigned long resultjiffies;
655static int resultsize;
656static unsigned long lastredo;
657
658static struct output_log {
659 unsigned char data;
660 unsigned char status;
661 unsigned long jiffies;
662} output_log[OLOGSIZE];
663
664static int output_log_pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
666#define current_reqD -1
667#define MAXTIMEOUT -2
668
Joe Perches73507e62010-03-10 15:21:03 -0800669static void __reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670{
671 if (drive == current_reqD)
672 drive = current_drive;
673 del_timer(&fd_timeout);
Eric Sesterhenn / Snakebyte4acb3e22007-05-23 13:58:15 -0700674 if (drive < 0 || drive >= N_DRIVE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 fd_timeout.expires = jiffies + 20UL * HZ;
676 drive = 0;
677 } else
678 fd_timeout.expires = jiffies + UDP->timeout;
679 add_timer(&fd_timeout);
Joe Perchesa81ee542010-03-10 15:20:46 -0800680 if (UDP->flags & FD_DEBUG)
Joe Perches73507e62010-03-10 15:21:03 -0800681 DPRINT("reschedule timeout %s\n", message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 timeout_message = message;
683}
684
Joe Perches73507e62010-03-10 15:21:03 -0800685static void reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686{
687 unsigned long flags;
688
689 spin_lock_irqsave(&floppy_lock, flags);
Joe Perches73507e62010-03-10 15:21:03 -0800690 __reschedule_timeout(drive, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 spin_unlock_irqrestore(&floppy_lock, flags);
692}
693
Joe Perches48c8cee2010-03-10 15:20:45 -0800694#define INFBOUND(a, b) (a) = max_t(int, a, b)
695#define SUPBOUND(a, b) (a) = min_t(int, a, b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696
697/*
698 * Bottom half floppy driver.
699 * ==========================
700 *
701 * This part of the file contains the code talking directly to the hardware,
702 * and also the main service loop (seek-configure-spinup-command)
703 */
704
705/*
706 * disk change.
707 * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
708 * and the last_checked date.
709 *
710 * last_checked is the date of the last check which showed 'no disk change'
711 * FD_DISK_CHANGE is set under two conditions:
712 * 1. The floppy has been changed after some i/o to that floppy already
713 * took place.
714 * 2. No floppy disk is in the drive. This is done in order to ensure that
715 * requests are quickly flushed in case there is no disk in the drive. It
716 * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
717 * the drive.
718 *
719 * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
720 * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
721 * each seek. If a disk is present, the disk change line should also be
722 * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
723 * change line is set, this means either that no disk is in the drive, or
724 * that it has been removed since the last seek.
725 *
726 * This means that we really have a third possibility too:
727 * The floppy has been changed after the last seek.
728 */
729
730static int disk_change(int drive)
731{
732 int fdc = FDC(drive);
Jesper Juhl06f748c2007-10-16 23:30:57 -0700733
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800734 if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 DPRINT("WARNING disk change called early\n");
736 if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
737 (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
738 DPRINT("probing disk change on unselected drive\n");
739 DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
740 (unsigned int)FDCS->dor);
741 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
Joe Perches87f530d2010-03-10 15:20:54 -0800743 debug_dcl(UDP->flags,
744 "checking disk change line for drive %d\n", drive);
745 debug_dcl(UDP->flags, "jiffies=%lu\n", jiffies);
746 debug_dcl(UDP->flags, "disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
747 debug_dcl(UDP->flags, "flags=%lx\n", UDRS->flags);
748
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 if (UDP->flags & FD_BROKEN_DCL)
Joe Perchese0298532010-03-10 15:20:55 -0800750 return test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
Joe Perchese0298532010-03-10 15:20:55 -0800752 set_bit(FD_VERIFY_BIT, &UDRS->flags);
753 /* verify write protection */
754
755 if (UDRS->maxblock) /* mark it changed */
756 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757
758 /* invalidate its geometry */
759 if (UDRS->keep_data >= 0) {
760 if ((UDP->flags & FTD_MSG) &&
761 current_type[drive] != NULL)
Joe Perches891eda82010-03-10 15:21:05 -0800762 DPRINT("Disk type is undefined after disk change\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 current_type[drive] = NULL;
764 floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
765 }
766
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 return 1;
768 } else {
769 UDRS->last_checked = jiffies;
Joe Perchese0298532010-03-10 15:20:55 -0800770 clear_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 }
772 return 0;
773}
774
775static inline int is_selected(int dor, int unit)
776{
777 return ((dor & (0x10 << unit)) && (dor & 3) == unit);
778}
779
Joe Perches57584c52010-03-10 15:21:00 -0800780static bool is_ready_state(int status)
781{
782 int state = status & (STATUS_READY | STATUS_DIR | STATUS_DMA);
783 return state == STATUS_READY;
784}
785
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786static int set_dor(int fdc, char mask, char data)
787{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700788 unsigned char unit;
789 unsigned char drive;
790 unsigned char newdor;
791 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792
793 if (FDCS->address == -1)
794 return -1;
795
796 olddor = FDCS->dor;
797 newdor = (olddor & mask) | data;
798 if (newdor != olddor) {
799 unit = olddor & 0x3;
800 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
801 drive = REVDRIVE(fdc, unit);
Joe Perches87f530d2010-03-10 15:20:54 -0800802 debug_dcl(UDP->flags,
803 "calling disk change from set_dor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 disk_change(drive);
805 }
806 FDCS->dor = newdor;
807 fd_outb(newdor, FD_DOR);
808
809 unit = newdor & 0x3;
810 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
811 drive = REVDRIVE(fdc, unit);
812 UDRS->select_date = jiffies;
813 }
814 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 return olddor;
816}
817
818static void twaddle(void)
819{
820 if (DP->select_delay)
821 return;
822 fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
823 fd_outb(FDCS->dor, FD_DOR);
824 DRS->select_date = jiffies;
825}
826
Joe Perches57584c52010-03-10 15:21:00 -0800827/*
828 * Reset all driver information about the current fdc.
829 * This is needed after a reset, and after a raw command.
830 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831static void reset_fdc_info(int mode)
832{
833 int drive;
834
835 FDCS->spec1 = FDCS->spec2 = -1;
836 FDCS->need_configure = 1;
837 FDCS->perp_mode = 1;
838 FDCS->rawcmd = 0;
839 for (drive = 0; drive < N_DRIVE; drive++)
840 if (FDC(drive) == fdc && (mode || UDRS->track != NEED_1_RECAL))
841 UDRS->track = NEED_2_RECAL;
842}
843
844/* selects the fdc and drive, and enables the fdc's input/dma. */
845static void set_fdc(int drive)
846{
847 if (drive >= 0 && drive < N_DRIVE) {
848 fdc = FDC(drive);
849 current_drive = drive;
850 }
851 if (fdc != 1 && fdc != 0) {
Joe Perchesb46df352010-03-10 15:20:46 -0800852 pr_info("bad fdc value\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 return;
854 }
855 set_dor(fdc, ~0, 8);
856#if N_FDC > 1
857 set_dor(1 - fdc, ~8, 0);
858#endif
859 if (FDCS->rawcmd == 2)
860 reset_fdc_info(1);
861 if (fd_inb(FD_STATUS) != STATUS_READY)
862 FDCS->reset = 1;
863}
864
865/* locks the driver */
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200866static int lock_fdc(int drive, bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867{
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200868 if (WARN(atomic_read(&usage_count) == 0,
869 "Trying to lock fdc while usage count=0\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200872 if (wait_event_interruptible(fdc_wait, !test_and_set_bit(0, &fdc_busy)))
873 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 command_status = FD_COMMAND_NONE;
876
Joe Perches73507e62010-03-10 15:21:03 -0800877 __reschedule_timeout(drive, "lock fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 set_fdc(drive);
879 return 0;
880}
881
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882/* unlocks the driver */
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +0200883static void unlock_fdc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884{
885 unsigned long flags;
886
887 raw_cmd = NULL;
888 if (!test_bit(0, &fdc_busy))
889 DPRINT("FDC access conflict!\n");
890
891 if (do_floppy)
Joe Perches1ebddd82010-03-10 15:21:07 -0800892 DPRINT("device interrupt still active at FDC release: %pf!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 do_floppy);
894 command_status = FD_COMMAND_NONE;
895 spin_lock_irqsave(&floppy_lock, flags);
896 del_timer(&fd_timeout);
897 cont = NULL;
898 clear_bit(0, &fdc_busy);
Jens Axboe48821182010-09-22 09:32:36 +0200899 if (current_req || set_next_request())
900 do_fd_request(current_req->q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 spin_unlock_irqrestore(&floppy_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 wake_up(&fdc_wait);
903}
904
905/* switches the motor off after a given timeout */
906static void motor_off_callback(unsigned long nr)
907{
908 unsigned char mask = ~(0x10 << UNIT(nr));
909
910 set_dor(FDC(nr), mask, 0);
911}
912
913/* schedules motor off */
914static void floppy_off(unsigned int drive)
915{
916 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700917 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
919 if (!(FDCS->dor & (0x10 << UNIT(drive))))
920 return;
921
922 del_timer(motor_off_timer + drive);
923
924 /* make spindle stop in a position which minimizes spinup time
925 * next time */
926 if (UDP->rps) {
927 delta = jiffies - UDRS->first_read_date + HZ -
928 UDP->spindown_offset;
929 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
930 motor_off_timer[drive].expires =
931 jiffies + UDP->spindown - delta;
932 }
933 add_timer(motor_off_timer + drive);
934}
935
936/*
937 * cycle through all N_DRIVE floppy drives, for disk change testing.
938 * stopping at current drive. This is done before any long operation, to
939 * be sure to have up to date disk change information.
940 */
941static void scandrives(void)
942{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700943 int i;
944 int drive;
945 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946
947 if (DP->select_delay)
948 return;
949
950 saved_drive = current_drive;
951 for (i = 0; i < N_DRIVE; i++) {
952 drive = (saved_drive + i + 1) % N_DRIVE;
953 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
954 continue; /* skip closed drives */
955 set_fdc(drive);
956 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
957 (0x10 << UNIT(drive))))
958 /* switch the motor off again, if it was off to
959 * begin with */
960 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
961 }
962 set_fdc(saved_drive);
963}
964
965static void empty(void)
966{
967}
968
David Howells65f27f32006-11-22 14:55:48 +0000969static DECLARE_WORK(floppy_work, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Joe Perches48c8cee2010-03-10 15:20:45 -0800971static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972{
David Howells65f27f32006-11-22 14:55:48 +0000973 PREPARE_WORK(&floppy_work, (work_func_t)handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 schedule_work(&floppy_work);
975}
976
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700977static DEFINE_TIMER(fd_timer, NULL, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978
979static void cancel_activity(void)
980{
981 unsigned long flags;
982
983 spin_lock_irqsave(&floppy_lock, flags);
984 do_floppy = NULL;
David Howells65f27f32006-11-22 14:55:48 +0000985 PREPARE_WORK(&floppy_work, (work_func_t)empty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 del_timer(&fd_timer);
987 spin_unlock_irqrestore(&floppy_lock, flags);
988}
989
990/* this function makes sure that the disk stays in the drive during the
991 * transfer */
992static void fd_watchdog(void)
993{
Joe Perches87f530d2010-03-10 15:20:54 -0800994 debug_dcl(DP->flags, "calling disk change from watchdog\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
996 if (disk_change(current_drive)) {
997 DPRINT("disk removed during i/o\n");
998 cancel_activity();
999 cont->done(0);
1000 reset_fdc();
1001 } else {
1002 del_timer(&fd_timer);
Joe Perchesa0a52d62010-03-10 15:20:52 -08001003 fd_timer.function = (timeout_fn)fd_watchdog;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 fd_timer.expires = jiffies + HZ / 10;
1005 add_timer(&fd_timer);
1006 }
1007}
1008
1009static void main_command_interrupt(void)
1010{
1011 del_timer(&fd_timer);
1012 cont->interrupt();
1013}
1014
1015/* waits for a delay (spinup or select) to pass */
1016static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
1017{
1018 if (FDCS->reset) {
1019 reset_fdc(); /* do the reset during sleep to win time
1020 * if we don't need to sleep, it's a good
1021 * occasion anyways */
1022 return 1;
1023 }
1024
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001025 if (time_before(jiffies, delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 del_timer(&fd_timer);
1027 fd_timer.function = function;
1028 fd_timer.expires = delay;
1029 add_timer(&fd_timer);
1030 return 1;
1031 }
1032 return 0;
1033}
1034
1035static DEFINE_SPINLOCK(floppy_hlt_lock);
1036static int hlt_disabled;
1037static void floppy_disable_hlt(void)
1038{
1039 unsigned long flags;
1040
Len Brown3b70b2e2011-04-01 15:08:48 -04001041 WARN_ONCE(1, "floppy_disable_hlt() scheduled for removal in 2012");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 spin_lock_irqsave(&floppy_hlt_lock, flags);
1043 if (!hlt_disabled) {
1044 hlt_disabled = 1;
1045#ifdef HAVE_DISABLE_HLT
1046 disable_hlt();
1047#endif
1048 }
1049 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1050}
1051
1052static void floppy_enable_hlt(void)
1053{
1054 unsigned long flags;
1055
1056 spin_lock_irqsave(&floppy_hlt_lock, flags);
1057 if (hlt_disabled) {
1058 hlt_disabled = 0;
1059#ifdef HAVE_DISABLE_HLT
1060 enable_hlt();
1061#endif
1062 }
1063 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1064}
1065
1066static void setup_DMA(void)
1067{
1068 unsigned long f;
1069
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 if (raw_cmd->length == 0) {
1071 int i;
1072
Joe Perchesb46df352010-03-10 15:20:46 -08001073 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001075 pr_cont("%x,", raw_cmd->cmd[i]);
1076 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 cont->done(0);
1078 FDCS->reset = 1;
1079 return;
1080 }
1081 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001082 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 cont->done(0);
1084 FDCS->reset = 1;
1085 return;
1086 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 f = claim_dma_lock();
1088 fd_disable_dma();
1089#ifdef fd_dma_setup
1090 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1091 (raw_cmd->flags & FD_RAW_READ) ?
1092 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1093 release_dma_lock(f);
1094 cont->done(0);
1095 FDCS->reset = 1;
1096 return;
1097 }
1098 release_dma_lock(f);
1099#else
1100 fd_clear_dma_ff();
1101 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1102 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1103 DMA_MODE_READ : DMA_MODE_WRITE);
1104 fd_set_dma_addr(raw_cmd->kernel_data);
1105 fd_set_dma_count(raw_cmd->length);
1106 virtual_dma_port = FDCS->address;
1107 fd_enable_dma();
1108 release_dma_lock(f);
1109#endif
1110 floppy_disable_hlt();
1111}
1112
1113static void show_floppy(void);
1114
1115/* waits until the fdc becomes ready */
1116static int wait_til_ready(void)
1117{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001118 int status;
1119 int counter;
1120
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 if (FDCS->reset)
1122 return -1;
1123 for (counter = 0; counter < 10000; counter++) {
1124 status = fd_inb(FD_STATUS);
1125 if (status & STATUS_READY)
1126 return status;
1127 }
Joe Perches29f1c782010-03-10 15:21:00 -08001128 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1130 show_floppy();
1131 }
1132 FDCS->reset = 1;
1133 return -1;
1134}
1135
1136/* sends a command byte to the fdc */
1137static int output_byte(char byte)
1138{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001139 int status = wait_til_ready();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001141 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001143
1144 if (is_ready_state(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 fd_outb(byte, FD_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 output_log[output_log_pos].data = byte;
1147 output_log[output_log_pos].status = status;
1148 output_log[output_log_pos].jiffies = jiffies;
1149 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 return 0;
1151 }
1152 FDCS->reset = 1;
Joe Perches29f1c782010-03-10 15:21:00 -08001153 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1155 byte, fdc, status);
1156 show_floppy();
1157 }
1158 return -1;
1159}
1160
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161/* gets the response from the fdc */
1162static int result(void)
1163{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001164 int i;
1165 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166
1167 for (i = 0; i < MAX_REPLIES; i++) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001168 status = wait_til_ready();
1169 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 break;
1171 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1172 if ((status & ~STATUS_BUSY) == STATUS_READY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 resultjiffies = jiffies;
1174 resultsize = i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 return i;
1176 }
1177 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1178 reply_buffer[i] = fd_inb(FD_DATA);
1179 else
1180 break;
1181 }
Joe Perches29f1c782010-03-10 15:21:00 -08001182 if (initialized) {
1183 DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1184 fdc, status, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 show_floppy();
1186 }
1187 FDCS->reset = 1;
1188 return -1;
1189}
1190
1191#define MORE_OUTPUT -2
1192/* does the fdc need more output? */
1193static int need_more_output(void)
1194{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001195 int status = wait_til_ready();
Jesper Juhl06f748c2007-10-16 23:30:57 -07001196
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001197 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001199
1200 if (is_ready_state(status))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 return MORE_OUTPUT;
Joe Perches57584c52010-03-10 15:21:00 -08001202
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 return result();
1204}
1205
1206/* Set perpendicular mode as required, based on data rate, if supported.
1207 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1208 */
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02001209static void perpendicular_mode(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210{
1211 unsigned char perp_mode;
1212
1213 if (raw_cmd->rate & 0x40) {
1214 switch (raw_cmd->rate & 3) {
1215 case 0:
1216 perp_mode = 2;
1217 break;
1218 case 3:
1219 perp_mode = 3;
1220 break;
1221 default:
1222 DPRINT("Invalid data rate for perpendicular mode!\n");
1223 cont->done(0);
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001224 FDCS->reset = 1;
1225 /*
1226 * convenient way to return to
1227 * redo without too much hassle
1228 * (deep stack et al.)
1229 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 return;
1231 }
1232 } else
1233 perp_mode = 0;
1234
1235 if (FDCS->perp_mode == perp_mode)
1236 return;
1237 if (FDCS->version >= FDC_82077_ORIG) {
1238 output_byte(FD_PERPENDICULAR);
1239 output_byte(perp_mode);
1240 FDCS->perp_mode = perp_mode;
1241 } else if (perp_mode) {
1242 DPRINT("perpendicular mode not supported by this FDC.\n");
1243 }
1244} /* perpendicular_mode */
1245
1246static int fifo_depth = 0xa;
1247static int no_fifo;
1248
1249static int fdc_configure(void)
1250{
1251 /* Turn on FIFO */
1252 output_byte(FD_CONFIGURE);
1253 if (need_more_output() != MORE_OUTPUT)
1254 return 0;
1255 output_byte(0);
1256 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1257 output_byte(0); /* pre-compensation from track
1258 0 upwards */
1259 return 1;
1260}
1261
1262#define NOMINAL_DTR 500
1263
1264/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1265 * head load time, and DMA disable flag to values needed by floppy.
1266 *
1267 * The value "dtr" is the data transfer rate in Kbps. It is needed
1268 * to account for the data rate-based scaling done by the 82072 and 82077
1269 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1270 * 8272a).
1271 *
1272 * Note that changing the data transfer rate has a (probably deleterious)
1273 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1274 * fdc_specify is called again after each data transfer rate
1275 * change.
1276 *
1277 * srt: 1000 to 16000 in microseconds
1278 * hut: 16 to 240 milliseconds
1279 * hlt: 2 to 254 milliseconds
1280 *
1281 * These values are rounded up to the next highest available delay time.
1282 */
1283static void fdc_specify(void)
1284{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001285 unsigned char spec1;
1286 unsigned char spec2;
1287 unsigned long srt;
1288 unsigned long hlt;
1289 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 unsigned long dtr = NOMINAL_DTR;
1291 unsigned long scale_dtr = NOMINAL_DTR;
1292 int hlt_max_code = 0x7f;
1293 int hut_max_code = 0xf;
1294
1295 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1296 fdc_configure();
1297 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 }
1299
1300 switch (raw_cmd->rate & 0x03) {
1301 case 3:
1302 dtr = 1000;
1303 break;
1304 case 1:
1305 dtr = 300;
1306 if (FDCS->version >= FDC_82078) {
1307 /* chose the default rate table, not the one
1308 * where 1 = 2 Mbps */
1309 output_byte(FD_DRIVESPEC);
1310 if (need_more_output() == MORE_OUTPUT) {
1311 output_byte(UNIT(current_drive));
1312 output_byte(0xc0);
1313 }
1314 }
1315 break;
1316 case 2:
1317 dtr = 250;
1318 break;
1319 }
1320
1321 if (FDCS->version >= FDC_82072) {
1322 scale_dtr = dtr;
1323 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1324 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1325 }
1326
1327 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001328 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001329 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001331
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 SUPBOUND(srt, 0xf);
1333 INFBOUND(srt, 0);
1334
Julia Lawall061837b2008-09-22 14:57:16 -07001335 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 if (hlt < 0x01)
1337 hlt = 0x01;
1338 else if (hlt > 0x7f)
1339 hlt = hlt_max_code;
1340
Julia Lawall061837b2008-09-22 14:57:16 -07001341 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 if (hut < 0x1)
1343 hut = 0x1;
1344 else if (hut > 0xf)
1345 hut = hut_max_code;
1346
1347 spec1 = (srt << 4) | hut;
1348 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1349
1350 /* If these parameters did not change, just return with success */
1351 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1352 /* Go ahead and set spec1 and spec2 */
1353 output_byte(FD_SPECIFY);
1354 output_byte(FDCS->spec1 = spec1);
1355 output_byte(FDCS->spec2 = spec2);
1356 }
1357} /* fdc_specify */
1358
1359/* Set the FDC's data transfer rate on behalf of the specified drive.
1360 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1361 * of the specify command (i.e. using the fdc_specify function).
1362 */
1363static int fdc_dtr(void)
1364{
1365 /* If data rate not already set to desired value, set it. */
1366 if ((raw_cmd->rate & 3) == FDCS->dtr)
1367 return 0;
1368
1369 /* Set dtr */
1370 fd_outb(raw_cmd->rate & 3, FD_DCR);
1371
1372 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1373 * need a stabilization period of several milliseconds to be
1374 * enforced after data rate changes before R/W operations.
1375 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1376 */
1377 FDCS->dtr = raw_cmd->rate & 3;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001378 return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
1379 (timeout_fn)floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380} /* fdc_dtr */
1381
1382static void tell_sector(void)
1383{
Joe Perchesb46df352010-03-10 15:20:46 -08001384 pr_cont(": track %d, head %d, sector %d, size %d",
1385 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386} /* tell_sector */
1387
Joe Perchesb46df352010-03-10 15:20:46 -08001388static void print_errors(void)
1389{
1390 DPRINT("");
1391 if (ST0 & ST0_ECE) {
1392 pr_cont("Recalibrate failed!");
1393 } else if (ST2 & ST2_CRC) {
1394 pr_cont("data CRC error");
1395 tell_sector();
1396 } else if (ST1 & ST1_CRC) {
1397 pr_cont("CRC error");
1398 tell_sector();
1399 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1400 (ST2 & ST2_MAM)) {
1401 if (!probing) {
1402 pr_cont("sector not found");
1403 tell_sector();
1404 } else
1405 pr_cont("probe failed...");
1406 } else if (ST2 & ST2_WC) { /* seek error */
1407 pr_cont("wrong cylinder");
1408 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1409 pr_cont("bad cylinder");
1410 } else {
1411 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1412 ST0, ST1, ST2);
1413 tell_sector();
1414 }
1415 pr_cont("\n");
1416}
1417
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418/*
1419 * OK, this error interpreting routine is called after a
1420 * DMA read/write has succeeded
1421 * or failed, so we check the results, and copy any buffers.
1422 * hhb: Added better error reporting.
1423 * ak: Made this into a separate routine.
1424 */
1425static int interpret_errors(void)
1426{
1427 char bad;
1428
1429 if (inr != 7) {
Joe Perches891eda82010-03-10 15:21:05 -08001430 DPRINT("-- FDC reply error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 FDCS->reset = 1;
1432 return 1;
1433 }
1434
1435 /* check IC to find cause of interrupt */
1436 switch (ST0 & ST0_INTR) {
1437 case 0x40: /* error occurred during command execution */
1438 if (ST1 & ST1_EOC)
1439 return 0; /* occurs with pseudo-DMA */
1440 bad = 1;
1441 if (ST1 & ST1_WP) {
1442 DPRINT("Drive is write protected\n");
Joe Perchese0298532010-03-10 15:20:55 -08001443 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 cont->done(0);
1445 bad = 2;
1446 } else if (ST1 & ST1_ND) {
Joe Perchese0298532010-03-10 15:20:55 -08001447 set_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 } else if (ST1 & ST1_OR) {
1449 if (DP->flags & FTD_MSG)
1450 DPRINT("Over/Underrun - retrying\n");
1451 bad = 0;
1452 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001453 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 }
1455 if (ST2 & ST2_WC || ST2 & ST2_BC)
1456 /* wrong cylinder => recal */
1457 DRS->track = NEED_2_RECAL;
1458 return bad;
1459 case 0x80: /* invalid command given */
1460 DPRINT("Invalid FDC command given!\n");
1461 cont->done(0);
1462 return 2;
1463 case 0xc0:
1464 DPRINT("Abnormal termination caused by polling\n");
1465 cont->error();
1466 return 2;
1467 default: /* (0) Normal command termination */
1468 return 0;
1469 }
1470}
1471
1472/*
1473 * This routine is called when everything should be correctly set up
1474 * for the transfer (i.e. floppy motor is on, the correct floppy is
1475 * selected, and the head is sitting on the right track).
1476 */
1477static void setup_rw_floppy(void)
1478{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001479 int i;
1480 int r;
1481 int flags;
1482 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 unsigned long ready_date;
1484 timeout_fn function;
1485
1486 flags = raw_cmd->flags;
1487 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1488 flags |= FD_RAW_INTR;
1489
1490 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1491 ready_date = DRS->spinup_date + DP->spinup;
1492 /* If spinup will take a long time, rerun scandrives
1493 * again just before spinup completion. Beware that
1494 * after scandrives, we must again wait for selection.
1495 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001496 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 ready_date -= DP->select_delay;
Joe Perchesa0a52d62010-03-10 15:20:52 -08001498 function = (timeout_fn)floppy_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 } else
Joe Perchesa0a52d62010-03-10 15:20:52 -08001500 function = (timeout_fn)setup_rw_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501
1502 /* wait until the floppy is spinning fast enough */
1503 if (fd_wait_for_completion(ready_date, function))
1504 return;
1505 }
1506 dflags = DRS->flags;
1507
1508 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1509 setup_DMA();
1510
1511 if (flags & FD_RAW_INTR)
1512 do_floppy = main_command_interrupt;
1513
1514 r = 0;
1515 for (i = 0; i < raw_cmd->cmd_count; i++)
1516 r |= output_byte(raw_cmd->cmd[i]);
1517
Joe Perchesded28632010-03-10 15:21:09 -08001518 debugt(__func__, "rw_command");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519
1520 if (r) {
1521 cont->error();
1522 reset_fdc();
1523 return;
1524 }
1525
1526 if (!(flags & FD_RAW_INTR)) {
1527 inr = result();
1528 cont->interrupt();
1529 } else if (flags & FD_RAW_NEED_DISK)
1530 fd_watchdog();
1531}
1532
1533static int blind_seek;
1534
1535/*
1536 * This is the routine called after every seek (or recalibrate) interrupt
1537 * from the floppy controller.
1538 */
1539static void seek_interrupt(void)
1540{
Joe Perchesded28632010-03-10 15:21:09 -08001541 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1543 DPRINT("seek failed\n");
1544 DRS->track = NEED_2_RECAL;
1545 cont->error();
1546 cont->redo();
1547 return;
1548 }
1549 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
Joe Perches87f530d2010-03-10 15:20:54 -08001550 debug_dcl(DP->flags,
1551 "clearing NEWCHANGE flag because of effective seek\n");
1552 debug_dcl(DP->flags, "jiffies=%lu\n", jiffies);
Joe Perchese0298532010-03-10 15:20:55 -08001553 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
1554 /* effective seek */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 DRS->select_date = jiffies;
1556 }
1557 DRS->track = ST1;
1558 floppy_ready();
1559}
1560
1561static void check_wp(void)
1562{
Joe Perchese0298532010-03-10 15:20:55 -08001563 if (test_bit(FD_VERIFY_BIT, &DRS->flags)) {
1564 /* check write protection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 output_byte(FD_GETSTATUS);
1566 output_byte(UNIT(current_drive));
1567 if (result() != 1) {
1568 FDCS->reset = 1;
1569 return;
1570 }
Joe Perchese0298532010-03-10 15:20:55 -08001571 clear_bit(FD_VERIFY_BIT, &DRS->flags);
1572 clear_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Joe Perches87f530d2010-03-10 15:20:54 -08001573 debug_dcl(DP->flags,
1574 "checking whether disk is write protected\n");
1575 debug_dcl(DP->flags, "wp=%x\n", ST3 & 0x40);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 if (!(ST3 & 0x40))
Joe Perchese0298532010-03-10 15:20:55 -08001577 set_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 else
Joe Perchese0298532010-03-10 15:20:55 -08001579 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 }
1581}
1582
1583static void seek_floppy(void)
1584{
1585 int track;
1586
1587 blind_seek = 0;
1588
Joe Perchesded28632010-03-10 15:21:09 -08001589 debug_dcl(DP->flags, "calling disk change from %s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590
Joe Perchese0298532010-03-10 15:20:55 -08001591 if (!test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1593 /* the media changed flag should be cleared after the seek.
1594 * If it isn't, this means that there is really no disk in
1595 * the drive.
1596 */
Joe Perchese0298532010-03-10 15:20:55 -08001597 set_bit(FD_DISK_CHANGED_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 cont->done(0);
1599 cont->redo();
1600 return;
1601 }
1602 if (DRS->track <= NEED_1_RECAL) {
1603 recalibrate_floppy();
1604 return;
Joe Perchese0298532010-03-10 15:20:55 -08001605 } else if (test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1607 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1608 /* we seek to clear the media-changed condition. Does anybody
1609 * know a more elegant way, which works on all drives? */
1610 if (raw_cmd->track)
1611 track = raw_cmd->track - 1;
1612 else {
1613 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1614 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1615 blind_seek = 1;
1616 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1617 }
1618 track = 1;
1619 }
1620 } else {
1621 check_wp();
1622 if (raw_cmd->track != DRS->track &&
1623 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1624 track = raw_cmd->track;
1625 else {
1626 setup_rw_floppy();
1627 return;
1628 }
1629 }
1630
1631 do_floppy = seek_interrupt;
1632 output_byte(FD_SEEK);
1633 output_byte(UNIT(current_drive));
Joe Perches2300f902010-03-10 15:20:49 -08001634 if (output_byte(track) < 0) {
1635 reset_fdc();
1636 return;
1637 }
Joe Perchesded28632010-03-10 15:21:09 -08001638 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639}
1640
1641static void recal_interrupt(void)
1642{
Joe Perchesded28632010-03-10 15:21:09 -08001643 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 if (inr != 2)
1645 FDCS->reset = 1;
1646 else if (ST0 & ST0_ECE) {
1647 switch (DRS->track) {
1648 case NEED_1_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001649 debugt(__func__, "need 1 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 /* after a second recalibrate, we still haven't
1651 * reached track 0. Probably no drive. Raise an
1652 * error, as failing immediately might upset
1653 * computers possessed by the Devil :-) */
1654 cont->error();
1655 cont->redo();
1656 return;
1657 case NEED_2_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001658 debugt(__func__, "need 2 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 /* If we already did a recalibrate,
1660 * and we are not at track 0, this
1661 * means we have moved. (The only way
1662 * not to move at recalibration is to
1663 * be already at track 0.) Clear the
1664 * new change flag */
Joe Perches87f530d2010-03-10 15:20:54 -08001665 debug_dcl(DP->flags,
1666 "clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667
Joe Perchese0298532010-03-10 15:20:55 -08001668 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 DRS->select_date = jiffies;
1670 /* fall through */
1671 default:
Joe Perchesded28632010-03-10 15:21:09 -08001672 debugt(__func__, "default");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 /* Recalibrate moves the head by at
1674 * most 80 steps. If after one
1675 * recalibrate we don't have reached
1676 * track 0, this might mean that we
1677 * started beyond track 80. Try
1678 * again. */
1679 DRS->track = NEED_1_RECAL;
1680 break;
1681 }
1682 } else
1683 DRS->track = ST1;
1684 floppy_ready();
1685}
1686
1687static void print_result(char *message, int inr)
1688{
1689 int i;
1690
1691 DPRINT("%s ", message);
1692 if (inr >= 0)
1693 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001694 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1695 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696}
1697
1698/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001699irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 int do_print;
1702 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001703 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704
1705 lasthandler = handler;
1706 interruptjiffies = jiffies;
1707
1708 f = claim_dma_lock();
1709 fd_disable_dma();
1710 release_dma_lock(f);
1711
1712 floppy_enable_hlt();
1713 do_floppy = NULL;
1714 if (fdc >= N_FDC || FDCS->address == -1) {
1715 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001716 pr_info("DOR0=%x\n", fdc_state[0].dor);
1717 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
Joe Perches1ebddd82010-03-10 15:21:07 -08001718 pr_info("handler=%pf\n", handler);
Joe Perches275176b2010-03-10 15:21:06 -08001719 is_alive(__func__, "bizarre fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 return IRQ_NONE;
1721 }
1722
1723 FDCS->reset = 0;
1724 /* We have to clear the reset flag here, because apparently on boxes
1725 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1726 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1727 * emission of the SENSEI's.
1728 * It is OK to emit floppy commands because we are in an interrupt
1729 * handler here, and thus we have to fear no interference of other
1730 * activity.
1731 */
1732
Joe Perches29f1c782010-03-10 15:21:00 -08001733 do_print = !handler && print_unex && initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734
1735 inr = result();
1736 if (do_print)
1737 print_result("unexpected interrupt", inr);
1738 if (inr == 0) {
1739 int max_sensei = 4;
1740 do {
1741 output_byte(FD_SENSEI);
1742 inr = result();
1743 if (do_print)
1744 print_result("sensei", inr);
1745 max_sensei--;
Joe Perchesc5297302010-03-10 15:20:58 -08001746 } while ((ST0 & 0x83) != UNIT(current_drive) &&
1747 inr == 2 && max_sensei);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 }
1749 if (!handler) {
1750 FDCS->reset = 1;
1751 return IRQ_NONE;
1752 }
1753 schedule_bh(handler);
Joe Perches275176b2010-03-10 15:21:06 -08001754 is_alive(__func__, "normal interrupt end");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755
1756 /* FIXME! Was it really for us? */
1757 return IRQ_HANDLED;
1758}
1759
1760static void recalibrate_floppy(void)
1761{
Joe Perchesded28632010-03-10 15:21:09 -08001762 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 do_floppy = recal_interrupt;
1764 output_byte(FD_RECALIBRATE);
Joe Perches15b26302010-03-10 15:21:01 -08001765 if (output_byte(UNIT(current_drive)) < 0)
Joe Perches2300f902010-03-10 15:20:49 -08001766 reset_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767}
1768
1769/*
1770 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1771 */
1772static void reset_interrupt(void)
1773{
Joe Perchesded28632010-03-10 15:21:09 -08001774 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 result(); /* get the status ready for set_fdc */
1776 if (FDCS->reset) {
Joe Perches1ebddd82010-03-10 15:21:07 -08001777 pr_info("reset set in interrupt, calling %pf\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 cont->error(); /* a reset just after a reset. BAD! */
1779 }
1780 cont->redo();
1781}
1782
1783/*
1784 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1785 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1786 */
1787static void reset_fdc(void)
1788{
1789 unsigned long flags;
1790
1791 do_floppy = reset_interrupt;
1792 FDCS->reset = 0;
1793 reset_fdc_info(0);
1794
1795 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1796 /* Irrelevant for systems with true DMA (i386). */
1797
1798 flags = claim_dma_lock();
1799 fd_disable_dma();
1800 release_dma_lock(flags);
1801
1802 if (FDCS->version >= FDC_82072A)
1803 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1804 else {
1805 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1806 udelay(FD_RESET_DELAY);
1807 fd_outb(FDCS->dor, FD_DOR);
1808 }
1809}
1810
1811static void show_floppy(void)
1812{
1813 int i;
1814
Joe Perchesb46df352010-03-10 15:20:46 -08001815 pr_info("\n");
1816 pr_info("floppy driver state\n");
1817 pr_info("-------------------\n");
Joe Perches1ebddd82010-03-10 15:21:07 -08001818 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%pf\n",
Joe Perchesb46df352010-03-10 15:20:46 -08001819 jiffies, interruptjiffies, jiffies - interruptjiffies,
1820 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821
Joe Perchesb46df352010-03-10 15:20:46 -08001822 pr_info("timeout_message=%s\n", timeout_message);
1823 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001825 pr_info("%2x %2x %lu\n",
1826 output_log[(i + output_log_pos) % OLOGSIZE].data,
1827 output_log[(i + output_log_pos) % OLOGSIZE].status,
1828 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1829 pr_info("last result at %lu\n", resultjiffies);
1830 pr_info("last redo_fd_request at %lu\n", lastredo);
1831 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1832 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833
Joe Perchesb46df352010-03-10 15:20:46 -08001834 pr_info("status=%x\n", fd_inb(FD_STATUS));
1835 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 if (do_floppy)
Joe Perches1ebddd82010-03-10 15:21:07 -08001837 pr_info("do_floppy=%pf\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001838 if (work_pending(&floppy_work))
Joe Perches1ebddd82010-03-10 15:21:07 -08001839 pr_info("floppy_work.func=%pf\n", floppy_work.func);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 if (timer_pending(&fd_timer))
Joe Perches1ebddd82010-03-10 15:21:07 -08001841 pr_info("fd_timer.function=%pf\n", fd_timer.function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 if (timer_pending(&fd_timeout)) {
Joe Perches1ebddd82010-03-10 15:21:07 -08001843 pr_info("timer_function=%pf\n", fd_timeout.function);
Joe Perchesb46df352010-03-10 15:20:46 -08001844 pr_info("expires=%lu\n", fd_timeout.expires - jiffies);
1845 pr_info("now=%lu\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 }
Joe Perchesb46df352010-03-10 15:20:46 -08001847 pr_info("cont=%p\n", cont);
1848 pr_info("current_req=%p\n", current_req);
1849 pr_info("command_status=%d\n", command_status);
1850 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851}
1852
1853static void floppy_shutdown(unsigned long data)
1854{
1855 unsigned long flags;
1856
Joe Perches29f1c782010-03-10 15:21:00 -08001857 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 show_floppy();
1859 cancel_activity();
1860
1861 floppy_enable_hlt();
1862
1863 flags = claim_dma_lock();
1864 fd_disable_dma();
1865 release_dma_lock(flags);
1866
1867 /* avoid dma going to a random drive after shutdown */
1868
Joe Perches29f1c782010-03-10 15:21:00 -08001869 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 DPRINT("floppy timeout called\n");
1871 FDCS->reset = 1;
1872 if (cont) {
1873 cont->done(0);
1874 cont->redo(); /* this will recall reset when needed */
1875 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001876 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 process_fd_request();
1878 }
Joe Perches275176b2010-03-10 15:21:06 -08001879 is_alive(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880}
1881
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001883static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001885 int mask;
1886 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887
1888 mask = 0xfc;
1889 data = UNIT(current_drive);
1890 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1891 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1892 set_debugt();
1893 /* no read since this drive is running */
1894 DRS->first_read_date = 0;
1895 /* note motor start time if motor is not yet running */
1896 DRS->spinup_date = jiffies;
1897 data |= (0x10 << UNIT(current_drive));
1898 }
1899 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1900 mask &= ~(0x10 << UNIT(current_drive));
1901
1902 /* starts motor and selects floppy */
1903 del_timer(motor_off_timer + current_drive);
1904 set_dor(fdc, mask, data);
1905
1906 /* wait_for_completion also schedules reset if needed. */
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001907 return fd_wait_for_completion(DRS->select_date + DP->select_delay,
1908 (timeout_fn)function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909}
1910
1911static void floppy_ready(void)
1912{
Joe Perches045f9832010-03-10 15:20:47 -08001913 if (FDCS->reset) {
1914 reset_fdc();
1915 return;
1916 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 if (start_motor(floppy_ready))
1918 return;
1919 if (fdc_dtr())
1920 return;
1921
Joe Perches87f530d2010-03-10 15:20:54 -08001922 debug_dcl(DP->flags, "calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1924 disk_change(current_drive) && !DP->select_delay)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001925 twaddle(); /* this clears the dcl on certain
1926 * drive/controller combinations */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927
1928#ifdef fd_chose_dma_mode
1929 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1930 unsigned long flags = claim_dma_lock();
1931 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1932 release_dma_lock(flags);
1933 }
1934#endif
1935
1936 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1937 perpendicular_mode();
1938 fdc_specify(); /* must be done here because of hut, hlt ... */
1939 seek_floppy();
1940 } else {
1941 if ((raw_cmd->flags & FD_RAW_READ) ||
1942 (raw_cmd->flags & FD_RAW_WRITE))
1943 fdc_specify();
1944 setup_rw_floppy();
1945 }
1946}
1947
1948static void floppy_start(void)
1949{
Joe Perches73507e62010-03-10 15:21:03 -08001950 reschedule_timeout(current_reqD, "floppy start");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951
1952 scandrives();
Joe Perches87f530d2010-03-10 15:20:54 -08001953 debug_dcl(DP->flags, "setting NEWCHANGE in floppy_start\n");
Joe Perchese0298532010-03-10 15:20:55 -08001954 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 floppy_ready();
1956}
1957
1958/*
1959 * ========================================================================
1960 * here ends the bottom half. Exported routines are:
1961 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
1962 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
1963 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
1964 * and set_dor.
1965 * ========================================================================
1966 */
1967/*
1968 * General purpose continuations.
1969 * ==============================
1970 */
1971
1972static void do_wakeup(void)
1973{
Joe Perches73507e62010-03-10 15:21:03 -08001974 reschedule_timeout(MAXTIMEOUT, "do wakeup");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 cont = NULL;
1976 command_status += 2;
1977 wake_up(&command_done);
1978}
1979
Stephen Hemminger3b06c212010-07-20 20:09:00 -06001980static const struct cont_t wakeup_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 .interrupt = empty,
1982 .redo = do_wakeup,
1983 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07001984 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985};
1986
Stephen Hemminger3b06c212010-07-20 20:09:00 -06001987static const struct cont_t intr_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 .interrupt = empty,
1989 .redo = process_fd_request,
1990 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07001991 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992};
1993
Joe Perches74f63f42010-03-10 15:20:58 -08001994static int wait_til_done(void (*handler)(void), bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995{
1996 int ret;
1997
1998 schedule_bh(handler);
1999
Stephen Hemmingerb862f262010-06-15 13:21:11 +02002000 if (interruptible)
2001 wait_event_interruptible(command_done, command_status >= 2);
2002 else
2003 wait_event(command_done, command_status >= 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004
2005 if (command_status < 2) {
2006 cancel_activity();
2007 cont = &intr_cont;
2008 reset_fdc();
2009 return -EINTR;
2010 }
2011
2012 if (FDCS->reset)
2013 command_status = FD_COMMAND_ERROR;
2014 if (command_status == FD_COMMAND_OKAY)
2015 ret = 0;
2016 else
2017 ret = -EIO;
2018 command_status = FD_COMMAND_NONE;
2019 return ret;
2020}
2021
2022static void generic_done(int result)
2023{
2024 command_status = result;
2025 cont = &wakeup_cont;
2026}
2027
2028static void generic_success(void)
2029{
2030 cont->done(1);
2031}
2032
2033static void generic_failure(void)
2034{
2035 cont->done(0);
2036}
2037
2038static void success_and_wakeup(void)
2039{
2040 generic_success();
2041 cont->redo();
2042}
2043
2044/*
2045 * formatting and rw support.
2046 * ==========================
2047 */
2048
2049static int next_valid_format(void)
2050{
2051 int probed_format;
2052
2053 probed_format = DRS->probed_format;
2054 while (1) {
2055 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2056 DRS->probed_format = 0;
2057 return 1;
2058 }
2059 if (floppy_type[DP->autodetect[probed_format]].sect) {
2060 DRS->probed_format = probed_format;
2061 return 0;
2062 }
2063 probed_format++;
2064 }
2065}
2066
2067static void bad_flp_intr(void)
2068{
2069 int err_count;
2070
2071 if (probing) {
2072 DRS->probed_format++;
2073 if (!next_valid_format())
2074 return;
2075 }
2076 err_count = ++(*errors);
2077 INFBOUND(DRWE->badness, err_count);
2078 if (err_count > DP->max_errors.abort)
2079 cont->done(0);
2080 if (err_count > DP->max_errors.reset)
2081 FDCS->reset = 1;
2082 else if (err_count > DP->max_errors.recal)
2083 DRS->track = NEED_2_RECAL;
2084}
2085
2086static void set_floppy(int drive)
2087{
2088 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002089
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 if (type)
2091 _floppy = floppy_type + type;
2092 else
2093 _floppy = current_type[drive];
2094}
2095
2096/*
2097 * formatting support.
2098 * ===================
2099 */
2100static void format_interrupt(void)
2101{
2102 switch (interpret_errors()) {
2103 case 1:
2104 cont->error();
2105 case 2:
2106 break;
2107 case 0:
2108 cont->done(1);
2109 }
2110 cont->redo();
2111}
2112
Joe Perches48c8cee2010-03-10 15:20:45 -08002113#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002115
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116static void setup_format_params(int track)
2117{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002118 int n;
2119 int il;
2120 int count;
2121 int head_shift;
2122 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 struct fparm {
2124 unsigned char track, head, sect, size;
2125 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126
2127 raw_cmd = &default_raw_cmd;
2128 raw_cmd->track = track;
2129
Joe Perches48c8cee2010-03-10 15:20:45 -08002130 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2131 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 raw_cmd->rate = _floppy->rate & 0x43;
2133 raw_cmd->cmd_count = NR_F;
2134 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2135 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2136 F_SIZECODE = FD_SIZECODE(_floppy);
2137 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2138 F_GAP = _floppy->fmt_gap;
2139 F_FILL = FD_FILL_BYTE;
2140
2141 raw_cmd->kernel_data = floppy_track_buffer;
2142 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2143
2144 /* allow for about 30ms for data transport per track */
2145 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2146
2147 /* a ``cylinder'' is two tracks plus a little stepping time */
2148 track_shift = 2 * head_shift + 3;
2149
2150 /* position of logical sector 1 on this track */
2151 n = (track_shift * format_req.track + head_shift * format_req.head)
2152 % F_SECT_PER_TRACK;
2153
2154 /* determine interleave */
2155 il = 1;
2156 if (_floppy->fmt_gap < 0x22)
2157 il++;
2158
2159 /* initialize field */
2160 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2161 here[count].track = format_req.track;
2162 here[count].head = format_req.head;
2163 here[count].sect = 0;
2164 here[count].size = F_SIZECODE;
2165 }
2166 /* place logical sectors */
2167 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2168 here[n].sect = count;
2169 n = (n + il) % F_SECT_PER_TRACK;
2170 if (here[n].sect) { /* sector busy, find next free sector */
2171 ++n;
2172 if (n >= F_SECT_PER_TRACK) {
2173 n -= F_SECT_PER_TRACK;
2174 while (here[n].sect)
2175 ++n;
2176 }
2177 }
2178 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002179 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002181 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 }
2183}
2184
2185static void redo_format(void)
2186{
2187 buffer_track = -1;
2188 setup_format_params(format_req.track << STRETCH(_floppy));
2189 floppy_start();
Joe Perchesded28632010-03-10 15:21:09 -08002190 debugt(__func__, "queue format request");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191}
2192
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002193static const struct cont_t format_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 .interrupt = format_interrupt,
2195 .redo = redo_format,
2196 .error = bad_flp_intr,
2197 .done = generic_done
2198};
2199
2200static int do_format(int drive, struct format_descr *tmp_format_req)
2201{
2202 int ret;
2203
Joe Perches74f63f42010-03-10 15:20:58 -08002204 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08002205 return -EINTR;
2206
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 set_floppy(drive);
2208 if (!_floppy ||
2209 _floppy->track > DP->tracks ||
2210 tmp_format_req->track >= _floppy->track ||
2211 tmp_format_req->head >= _floppy->head ||
2212 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2213 !_floppy->fmt_gap) {
2214 process_fd_request();
2215 return -EINVAL;
2216 }
2217 format_req = *tmp_format_req;
2218 format_errors = 0;
2219 cont = &format_cont;
2220 errors = &format_errors;
Joe Perches74f63f42010-03-10 15:20:58 -08002221 ret = wait_til_done(redo_format, true);
Joe Perches55eee802010-03-10 15:20:57 -08002222 if (ret == -EINTR)
2223 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 process_fd_request();
2225 return ret;
2226}
2227
2228/*
2229 * Buffer read/write and support
2230 * =============================
2231 */
2232
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002233static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234{
2235 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002236 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237
2238 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002239 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002240 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002241 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243
2244 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002245 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 current_req = NULL;
2247}
2248
2249/* new request_done. Can handle physical sectors which are smaller than a
2250 * logical buffer */
2251static void request_done(int uptodate)
2252{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 struct request *req = current_req;
Jens Axboe48821182010-09-22 09:32:36 +02002254 struct request_queue *q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 unsigned long flags;
2256 int block;
Joe Perches73507e62010-03-10 15:21:03 -08002257 char msg[sizeof("request done ") + sizeof(int) * 3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258
2259 probing = 0;
Joe Perches73507e62010-03-10 15:21:03 -08002260 snprintf(msg, sizeof(msg), "request done %d", uptodate);
2261 reschedule_timeout(MAXTIMEOUT, msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262
2263 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002264 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 return;
2266 }
2267
Jens Axboe48821182010-09-22 09:32:36 +02002268 q = req->q;
2269
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 if (uptodate) {
2271 /* maintain values for invalidation on geometry
2272 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002273 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 INFBOUND(DRS->maxblock, block);
2275 if (block > _floppy->sect)
2276 DRS->maxtrack = 1;
2277
2278 /* unlock chained buffers */
2279 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002280 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 spin_unlock_irqrestore(q->queue_lock, flags);
2282 } else {
2283 if (rq_data_dir(req) == WRITE) {
2284 /* record write error information */
2285 DRWE->write_errors++;
2286 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002287 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 DRWE->first_error_generation = DRS->generation;
2289 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002290 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 DRWE->last_error_generation = DRS->generation;
2292 }
2293 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002294 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 spin_unlock_irqrestore(q->queue_lock, flags);
2296 }
2297}
2298
2299/* Interrupt handler evaluating the result of the r/w operation */
2300static void rw_interrupt(void)
2301{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002302 int eoc;
2303 int ssize;
2304 int heads;
2305 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306
2307 if (R_HEAD >= 2) {
2308 /* some Toshiba floppy controllers occasionnally seem to
2309 * return bogus interrupts after read/write operations, which
2310 * can be recognized by a bad head number (>= 2) */
2311 return;
2312 }
2313
2314 if (!DRS->first_read_date)
2315 DRS->first_read_date = jiffies;
2316
2317 nr_sectors = 0;
Joe Perches712e1de2010-03-10 15:21:10 -08002318 ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319
2320 if (ST1 & ST1_EOC)
2321 eoc = 1;
2322 else
2323 eoc = 0;
2324
2325 if (COMMAND & 0x80)
2326 heads = 2;
2327 else
2328 heads = 1;
2329
2330 nr_sectors = (((R_TRACK - TRACK) * heads +
2331 R_HEAD - HEAD) * SECT_PER_TRACK +
2332 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2333
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002335 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 DPRINT("long rw: %x instead of %lx\n",
2337 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002338 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2339 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2340 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2341 pr_info("heads=%d eoc=%d\n", heads, eoc);
2342 pr_info("spt=%d st=%d ss=%d\n",
2343 SECT_PER_TRACK, fsector_t, ssize);
2344 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346
2347 nr_sectors -= in_sector_offset;
2348 INFBOUND(nr_sectors, 0);
2349 SUPBOUND(current_count_sectors, nr_sectors);
2350
2351 switch (interpret_errors()) {
2352 case 2:
2353 cont->redo();
2354 return;
2355 case 1:
2356 if (!current_count_sectors) {
2357 cont->error();
2358 cont->redo();
2359 return;
2360 }
2361 break;
2362 case 0:
2363 if (!current_count_sectors) {
2364 cont->redo();
2365 return;
2366 }
2367 current_type[current_drive] = _floppy;
2368 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2369 break;
2370 }
2371
2372 if (probing) {
2373 if (DP->flags & FTD_MSG)
2374 DPRINT("Auto-detected floppy type %s in fd%d\n",
2375 _floppy->name, current_drive);
2376 current_type[current_drive] = _floppy;
2377 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2378 probing = 0;
2379 }
2380
2381 if (CT(COMMAND) != FD_READ ||
2382 raw_cmd->kernel_data == current_req->buffer) {
2383 /* transfer directly from buffer */
2384 cont->done(1);
2385 } else if (CT(COMMAND) == FD_READ) {
2386 buffer_track = raw_cmd->track;
2387 buffer_drive = current_drive;
2388 INFBOUND(buffer_max, nr_sectors + fsector_t);
2389 }
2390 cont->redo();
2391}
2392
2393/* Compute maximal contiguous buffer size. */
2394static int buffer_chain_size(void)
2395{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 struct bio_vec *bv;
NeilBrown5705f702007-09-25 12:35:59 +02002397 int size;
2398 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 char *base;
2400
2401 base = bio_data(current_req->bio);
2402 size = 0;
2403
NeilBrown5705f702007-09-25 12:35:59 +02002404 rq_for_each_segment(bv, current_req, iter) {
2405 if (page_address(bv->bv_page) + bv->bv_offset != base + size)
2406 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407
NeilBrown5705f702007-09-25 12:35:59 +02002408 size += bv->bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 }
2410
2411 return size >> 9;
2412}
2413
2414/* Compute the maximal transfer size */
2415static int transfer_size(int ssize, int max_sector, int max_size)
2416{
2417 SUPBOUND(max_sector, fsector_t + max_size);
2418
2419 /* alignment */
2420 max_sector -= (max_sector % _floppy->sect) % ssize;
2421
2422 /* transfer size, beginning not aligned */
2423 current_count_sectors = max_sector - fsector_t;
2424
2425 return max_sector;
2426}
2427
2428/*
2429 * Move data from/to the track buffer to/from the buffer cache.
2430 */
2431static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2432{
2433 int remaining; /* number of transferred 512-byte sectors */
2434 struct bio_vec *bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002435 char *buffer;
2436 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002437 int size;
2438 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439
2440 max_sector = transfer_size(ssize,
2441 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002442 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443
2444 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002445 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002447 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448
2449 remaining = current_count_sectors << 9;
Tejun Heo1011c1b2009-05-07 22:24:45 +09002450 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002452 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2453 pr_info("remaining=%d\n", remaining >> 9);
2454 pr_info("current_req->nr_sectors=%u\n",
2455 blk_rq_sectors(current_req));
2456 pr_info("current_req->current_nr_sectors=%u\n",
2457 blk_rq_cur_sectors(current_req));
2458 pr_info("max_sector=%d\n", max_sector);
2459 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461
2462 buffer_max = max(max_sector, buffer_max);
2463
2464 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2465
Tejun Heo1011c1b2009-05-07 22:24:45 +09002466 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467
NeilBrown5705f702007-09-25 12:35:59 +02002468 rq_for_each_segment(bv, current_req, iter) {
2469 if (!remaining)
2470 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471
NeilBrown5705f702007-09-25 12:35:59 +02002472 size = bv->bv_len;
2473 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474
NeilBrown5705f702007-09-25 12:35:59 +02002475 buffer = page_address(bv->bv_page) + bv->bv_offset;
NeilBrown5705f702007-09-25 12:35:59 +02002476 if (dma_buffer + size >
2477 floppy_track_buffer + (max_buffer_sectors << 10) ||
2478 dma_buffer < floppy_track_buffer) {
2479 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002480 (int)((floppy_track_buffer - dma_buffer) >> 9));
2481 pr_info("fsector_t=%d buffer_min=%d\n",
2482 fsector_t, buffer_min);
2483 pr_info("current_count_sectors=%ld\n",
2484 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002486 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002487 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002488 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002489 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 }
NeilBrown5705f702007-09-25 12:35:59 +02002491 if (((unsigned long)buffer) % 512)
2492 DPRINT("%p buffer not aligned\n", buffer);
Joe Perches1a23d132010-03-10 15:21:04 -08002493
NeilBrown5705f702007-09-25 12:35:59 +02002494 if (CT(COMMAND) == FD_READ)
2495 memcpy(buffer, dma_buffer, size);
2496 else
2497 memcpy(dma_buffer, buffer, size);
2498
2499 remaining -= size;
2500 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 if (remaining) {
2503 if (remaining > 0)
2504 max_sector -= remaining >> 9;
2505 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2506 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507}
2508
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509/* work around a bug in pseudo DMA
2510 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2511 * sending data. Hence we need a different way to signal the
2512 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2513 * does not work with MT, hence we can only transfer one head at
2514 * a time
2515 */
2516static void virtualdmabug_workaround(void)
2517{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002518 int hard_sectors;
2519 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520
2521 if (CT(COMMAND) == FD_WRITE) {
2522 COMMAND &= ~0x80; /* switch off multiple track mode */
2523
2524 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2525 end_sector = SECTOR + hard_sectors - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002527 pr_info("too many sectors %d > %d\n",
2528 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 return;
2530 }
Joe Perches48c8cee2010-03-10 15:20:45 -08002531 SECT_PER_TRACK = end_sector;
2532 /* make sure SECT_PER_TRACK
2533 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 }
2535}
2536
2537/*
2538 * Formulate a read/write request.
2539 * this routine decides where to load the data (directly to buffer, or to
2540 * tmp floppy area), how much data to load (the size of the buffer, the whole
2541 * track, or a single sector)
2542 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2543 * allocation on the fly, it should be done here. No other part should need
2544 * modification.
2545 */
2546
2547static int make_raw_rw_request(void)
2548{
2549 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002550 int max_sector;
2551 int max_size;
2552 int tracksize;
2553 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002555 if (WARN(max_buffer_sectors == 0, "VFS: Block I/O scheduled on unopened device\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557
2558 set_fdc((long)current_req->rq_disk->private_data);
2559
2560 raw_cmd = &default_raw_cmd;
2561 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
2562 FD_RAW_NEED_SEEK;
2563 raw_cmd->cmd_count = NR_RW;
2564 if (rq_data_dir(current_req) == READ) {
2565 raw_cmd->flags |= FD_RAW_READ;
2566 COMMAND = FM_MODE(_floppy, FD_READ);
2567 } else if (rq_data_dir(current_req) == WRITE) {
2568 raw_cmd->flags |= FD_RAW_WRITE;
2569 COMMAND = FM_MODE(_floppy, FD_WRITE);
2570 } else {
Joe Perches275176b2010-03-10 15:21:06 -08002571 DPRINT("%s: unknown command\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 return 0;
2573 }
2574
2575 max_sector = _floppy->sect * _floppy->head;
2576
Tejun Heo83096eb2009-05-07 22:24:39 +09002577 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2578 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002580 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 current_count_sectors = 1;
2582 return 1;
2583 } else
2584 return 0;
2585 }
2586 HEAD = fsector_t / _floppy->sect;
2587
Keith Wansbrough9e491842008-09-22 14:57:17 -07002588 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Joe Perchese0298532010-03-10 15:20:55 -08002589 test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags)) &&
2590 fsector_t < _floppy->sect)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 max_sector = _floppy->sect;
2592
2593 /* 2M disks have phantom sectors on the first track */
2594 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2595 max_sector = 2 * _floppy->sect / 3;
2596 if (fsector_t >= max_sector) {
2597 current_count_sectors =
2598 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002599 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 return 1;
2601 }
2602 SIZECODE = 2;
2603 } else
2604 SIZECODE = FD_SIZECODE(_floppy);
2605 raw_cmd->rate = _floppy->rate & 0x43;
2606 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2607 raw_cmd->rate = 1;
2608
2609 if (SIZECODE)
2610 SIZECODE2 = 0xff;
2611 else
2612 SIZECODE2 = 0x80;
2613 raw_cmd->track = TRACK << STRETCH(_floppy);
2614 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2615 GAP = _floppy->gap;
Joe Perches712e1de2010-03-10 15:21:10 -08002616 ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2618 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002619 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620
2621 /* tracksize describes the size which can be filled up with sectors
2622 * of size ssize.
2623 */
2624 tracksize = _floppy->sect - _floppy->sect % ssize;
2625 if (tracksize < _floppy->sect) {
2626 SECT_PER_TRACK++;
2627 if (tracksize <= fsector_t % _floppy->sect)
2628 SECTOR--;
2629
2630 /* if we are beyond tracksize, fill up using smaller sectors */
2631 while (tracksize <= fsector_t % _floppy->sect) {
2632 while (tracksize + ssize > _floppy->sect) {
2633 SIZECODE--;
2634 ssize >>= 1;
2635 }
2636 SECTOR++;
2637 SECT_PER_TRACK++;
2638 tracksize += ssize;
2639 }
2640 max_sector = HEAD * _floppy->sect + tracksize;
2641 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2642 max_sector = _floppy->sect;
2643 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2644 /* for virtual DMA bug workaround */
2645 max_sector = _floppy->sect;
2646 }
2647
2648 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2649 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002650 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 if ((raw_cmd->track == buffer_track) &&
2652 (current_drive == buffer_drive) &&
2653 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2654 /* data already in track buffer */
2655 if (CT(COMMAND) == FD_READ) {
2656 copy_buffer(1, max_sector, buffer_max);
2657 return 1;
2658 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002659 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 if (CT(COMMAND) == FD_WRITE) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002661 unsigned int sectors;
2662
2663 sectors = fsector_t + blk_rq_sectors(current_req);
2664 if (sectors > ssize && sectors < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 max_size = ssize + ssize;
2666 else
2667 max_size = ssize;
2668 }
2669 raw_cmd->flags &= ~FD_RAW_WRITE;
2670 raw_cmd->flags |= FD_RAW_READ;
2671 COMMAND = FM_MODE(_floppy, FD_READ);
2672 } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) {
2673 unsigned long dma_limit;
2674 int direct, indirect;
2675
2676 indirect =
2677 transfer_size(ssize, max_sector,
2678 max_buffer_sectors * 2) - fsector_t;
2679
2680 /*
2681 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2682 * on a 64 bit machine!
2683 */
2684 max_size = buffer_chain_size();
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002685 dma_limit = (MAX_DMA_ADDRESS -
2686 ((unsigned long)current_req->buffer)) >> 9;
Joe Perchesa81ee542010-03-10 15:20:46 -08002687 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 /* 64 kb boundaries */
2690 if (CROSS_64KB(current_req->buffer, max_size << 9))
2691 max_size = (K_64 -
2692 ((unsigned long)current_req->buffer) %
2693 K_64) >> 9;
2694 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2695 /*
2696 * We try to read tracks, but if we get too many errors, we
2697 * go back to reading just one sector at a time.
2698 *
2699 * This means we should be able to read a sector even if there
2700 * are other bad sectors on this track.
2701 */
2702 if (!direct ||
2703 (indirect * 2 > direct * 3 &&
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002704 *errors < DP->max_errors.read_track &&
2705 ((!probing ||
2706 (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002707 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 } else {
2709 raw_cmd->kernel_data = current_req->buffer;
2710 raw_cmd->length = current_count_sectors << 9;
2711 if (raw_cmd->length == 0) {
Joe Perches275176b2010-03-10 15:21:06 -08002712 DPRINT("%s: zero dma transfer attempted\n", __func__);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002713 DPRINT("indirect=%d direct=%d fsector_t=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 indirect, direct, fsector_t);
2715 return 0;
2716 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 virtualdmabug_workaround();
2718 return 2;
2719 }
2720 }
2721
2722 if (CT(COMMAND) == FD_READ)
2723 max_size = max_sector; /* unbounded */
2724
2725 /* claim buffer track if needed */
2726 if (buffer_track != raw_cmd->track || /* bad track */
2727 buffer_drive != current_drive || /* bad drive */
2728 fsector_t > buffer_max ||
2729 fsector_t < buffer_min ||
2730 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002731 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 max_sector > 2 * max_buffer_sectors + buffer_min &&
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002733 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
2734 /* not enough space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 buffer_track = -1;
2736 buffer_drive = current_drive;
2737 buffer_max = buffer_min = aligned_sector_t;
2738 }
2739 raw_cmd->kernel_data = floppy_track_buffer +
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002740 ((aligned_sector_t - buffer_min) << 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741
2742 if (CT(COMMAND) == FD_WRITE) {
2743 /* copy write buffer to track buffer.
2744 * if we get here, we know that the write
2745 * is either aligned or the data already in the buffer
2746 * (buffer will be overwritten) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 if (in_sector_offset && buffer_track == -1)
2748 DPRINT("internal error offset !=0 on write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 buffer_track = raw_cmd->track;
2750 buffer_drive = current_drive;
2751 copy_buffer(ssize, max_sector,
2752 2 * max_buffer_sectors + buffer_min);
2753 } else
2754 transfer_size(ssize, max_sector,
2755 2 * max_buffer_sectors + buffer_min -
2756 aligned_sector_t);
2757
2758 /* round up current_count_sectors to get dma xfer size */
2759 raw_cmd->length = in_sector_offset + current_count_sectors;
2760 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2761 raw_cmd->length <<= 9;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 if ((raw_cmd->length < current_count_sectors << 9) ||
2763 (raw_cmd->kernel_data != current_req->buffer &&
2764 CT(COMMAND) == FD_WRITE &&
2765 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2766 aligned_sector_t < buffer_min)) ||
2767 raw_cmd->length % (128 << SIZECODE) ||
2768 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2769 DPRINT("fractionary current count b=%lx s=%lx\n",
2770 raw_cmd->length, current_count_sectors);
2771 if (raw_cmd->kernel_data != current_req->buffer)
Joe Perchesb46df352010-03-10 15:20:46 -08002772 pr_info("addr=%d, length=%ld\n",
2773 (int)((raw_cmd->kernel_data -
2774 floppy_track_buffer) >> 9),
2775 current_count_sectors);
2776 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2777 fsector_t, aligned_sector_t, max_sector, max_size);
2778 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2779 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2780 COMMAND, SECTOR, HEAD, TRACK);
2781 pr_info("buffer drive=%d\n", buffer_drive);
2782 pr_info("buffer track=%d\n", buffer_track);
2783 pr_info("buffer_min=%d\n", buffer_min);
2784 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 return 0;
2786 }
2787
2788 if (raw_cmd->kernel_data != current_req->buffer) {
2789 if (raw_cmd->kernel_data < floppy_track_buffer ||
2790 current_count_sectors < 0 ||
2791 raw_cmd->length < 0 ||
2792 raw_cmd->kernel_data + raw_cmd->length >
2793 floppy_track_buffer + (max_buffer_sectors << 10)) {
2794 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002795 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2796 fsector_t, buffer_min, raw_cmd->length >> 9);
2797 pr_info("current_count_sectors=%ld\n",
2798 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002800 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002802 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 return 0;
2804 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002805 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002806 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 DPRINT("buffer overrun in direct transfer\n");
2808 return 0;
2809 } else if (raw_cmd->length < current_count_sectors << 9) {
2810 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002811 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2812 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 }
2814 if (raw_cmd->length == 0) {
2815 DPRINT("zero dma transfer attempted from make_raw_request\n");
2816 return 0;
2817 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818
2819 virtualdmabug_workaround();
2820 return 2;
2821}
2822
Jens Axboe48821182010-09-22 09:32:36 +02002823/*
2824 * Round-robin between our available drives, doing one request from each
2825 */
2826static int set_next_request(void)
2827{
2828 struct request_queue *q;
2829 int old_pos = fdc_queue;
2830
2831 do {
2832 q = disks[fdc_queue]->queue;
2833 if (++fdc_queue == N_DRIVE)
2834 fdc_queue = 0;
2835 if (q) {
2836 current_req = blk_fetch_request(q);
2837 if (current_req)
2838 break;
2839 }
2840 } while (fdc_queue != old_pos);
2841
2842 return current_req != NULL;
2843}
2844
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845static void redo_fd_request(void)
2846{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 int drive;
2848 int tmp;
2849
2850 lastredo = jiffies;
2851 if (current_drive < N_DRIVE)
2852 floppy_off(current_drive);
2853
Joe Perches0da31322010-03-10 15:21:03 -08002854do_request:
2855 if (!current_req) {
Jens Axboe48821182010-09-22 09:32:36 +02002856 int pending;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857
Jens Axboe48821182010-09-22 09:32:36 +02002858 spin_lock_irq(&floppy_lock);
2859 pending = set_next_request();
2860 spin_unlock_irq(&floppy_lock);
2861
2862 if (!pending) {
Joe Perches0da31322010-03-10 15:21:03 -08002863 do_floppy = NULL;
2864 unlock_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 }
Joe Perches0da31322010-03-10 15:21:03 -08002868 drive = (long)current_req->rq_disk->private_data;
2869 set_fdc(drive);
Joe Perches73507e62010-03-10 15:21:03 -08002870 reschedule_timeout(current_reqD, "redo fd request");
Joe Perches0da31322010-03-10 15:21:03 -08002871
2872 set_floppy(drive);
2873 raw_cmd = &default_raw_cmd;
2874 raw_cmd->flags = 0;
2875 if (start_motor(redo_fd_request))
2876 return;
2877
2878 disk_change(current_drive);
2879 if (test_bit(current_drive, &fake_change) ||
2880 test_bit(FD_DISK_CHANGED_BIT, &DRS->flags)) {
2881 DPRINT("disk absent or changed during operation\n");
2882 request_done(0);
2883 goto do_request;
2884 }
2885 if (!_floppy) { /* Autodetection */
2886 if (!probing) {
2887 DRS->probed_format = 0;
2888 if (next_valid_format()) {
2889 DPRINT("no autodetectable formats\n");
2890 _floppy = NULL;
2891 request_done(0);
2892 goto do_request;
2893 }
2894 }
2895 probing = 1;
2896 _floppy = floppy_type + DP->autodetect[DRS->probed_format];
2897 } else
2898 probing = 0;
2899 errors = &(current_req->errors);
2900 tmp = make_raw_rw_request();
2901 if (tmp < 2) {
2902 request_done(tmp);
2903 goto do_request;
2904 }
2905
2906 if (test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags))
2907 twaddle();
2908 schedule_bh(floppy_start);
Joe Perchesded28632010-03-10 15:21:09 -08002909 debugt(__func__, "queue fd request");
Joe Perches0da31322010-03-10 15:21:03 -08002910 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911}
2912
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002913static const struct cont_t rw_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 .interrupt = rw_interrupt,
2915 .redo = redo_fd_request,
2916 .error = bad_flp_intr,
2917 .done = request_done
2918};
2919
2920static void process_fd_request(void)
2921{
2922 cont = &rw_cont;
2923 schedule_bh(redo_fd_request);
2924}
2925
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002926static void do_fd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927{
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002928 if (WARN(max_buffer_sectors == 0,
2929 "VFS: %s called on non-open device\n", __func__))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002932 if (WARN(atomic_read(&usage_count) == 0,
2933 "warning: usage count=0, current_req=%p sect=%ld type=%x flags=%x\n",
2934 current_req, (long)blk_rq_pos(current_req), current_req->cmd_type,
2935 current_req->cmd_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 return;
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002937
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 if (test_bit(0, &fdc_busy)) {
2939 /* fdc busy, this new request will be treated when the
2940 current one is done */
Joe Perches275176b2010-03-10 15:21:06 -08002941 is_alive(__func__, "old request running");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 return;
2943 }
Joe Perches74f63f42010-03-10 15:20:58 -08002944 lock_fdc(MAXTIMEOUT, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 process_fd_request();
Joe Perches275176b2010-03-10 15:21:06 -08002946 is_alive(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947}
2948
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002949static const struct cont_t poll_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 .interrupt = success_and_wakeup,
2951 .redo = floppy_ready,
2952 .error = generic_failure,
2953 .done = generic_done
2954};
2955
Joe Perches74f63f42010-03-10 15:20:58 -08002956static int poll_drive(bool interruptible, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 /* no auto-sense, just clear dcl */
2959 raw_cmd = &default_raw_cmd;
2960 raw_cmd->flags = flag;
2961 raw_cmd->track = 0;
2962 raw_cmd->cmd_count = 0;
2963 cont = &poll_cont;
Joe Perches87f530d2010-03-10 15:20:54 -08002964 debug_dcl(DP->flags, "setting NEWCHANGE in poll_drive\n");
Joe Perchese0298532010-03-10 15:20:55 -08002965 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Joe Perches55eee802010-03-10 15:20:57 -08002966
2967 return wait_til_done(floppy_ready, interruptible);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968}
2969
2970/*
2971 * User triggered reset
2972 * ====================
2973 */
2974
2975static void reset_intr(void)
2976{
Joe Perchesb46df352010-03-10 15:20:46 -08002977 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978}
2979
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002980static const struct cont_t reset_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 .interrupt = reset_intr,
2982 .redo = success_and_wakeup,
2983 .error = generic_failure,
2984 .done = generic_done
2985};
2986
Joe Perches74f63f42010-03-10 15:20:58 -08002987static int user_reset_fdc(int drive, int arg, bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988{
2989 int ret;
2990
Joe Perches52a0d612010-03-10 15:20:53 -08002991 if (lock_fdc(drive, interruptible))
2992 return -EINTR;
2993
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 if (arg == FD_RESET_ALWAYS)
2995 FDCS->reset = 1;
2996 if (FDCS->reset) {
2997 cont = &reset_cont;
Joe Perches55eee802010-03-10 15:20:57 -08002998 ret = wait_til_done(reset_fdc, interruptible);
2999 if (ret == -EINTR)
3000 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 }
3002 process_fd_request();
Joe Perches52a0d612010-03-10 15:20:53 -08003003 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004}
3005
3006/*
3007 * Misc Ioctl's and support
3008 * ========================
3009 */
3010static inline int fd_copyout(void __user *param, const void *address,
3011 unsigned long size)
3012{
3013 return copy_to_user(param, address, size) ? -EFAULT : 0;
3014}
3015
Joe Perches48c8cee2010-03-10 15:20:45 -08003016static inline int fd_copyin(void __user *param, void *address,
3017 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018{
3019 return copy_from_user(address, param, size) ? -EFAULT : 0;
3020}
3021
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003022static const char *drive_name(int type, int drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023{
3024 struct floppy_struct *floppy;
3025
3026 if (type)
3027 floppy = floppy_type + type;
3028 else {
3029 if (UDP->native_format)
3030 floppy = floppy_type + UDP->native_format;
3031 else
3032 return "(null)";
3033 }
3034 if (floppy->name)
3035 return floppy->name;
3036 else
3037 return "(null)";
3038}
3039
3040/* raw commands */
3041static void raw_cmd_done(int flag)
3042{
3043 int i;
3044
3045 if (!flag) {
3046 raw_cmd->flags |= FD_RAW_FAILURE;
3047 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3048 } else {
3049 raw_cmd->reply_count = inr;
3050 if (raw_cmd->reply_count > MAX_REPLIES)
3051 raw_cmd->reply_count = 0;
3052 for (i = 0; i < raw_cmd->reply_count; i++)
3053 raw_cmd->reply[i] = reply_buffer[i];
3054
3055 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3056 unsigned long flags;
3057 flags = claim_dma_lock();
3058 raw_cmd->length = fd_get_dma_residue();
3059 release_dma_lock(flags);
3060 }
3061
3062 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3063 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3064 raw_cmd->flags |= FD_RAW_FAILURE;
3065
3066 if (disk_change(current_drive))
3067 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3068 else
3069 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3070 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3071 motor_off_callback(current_drive);
3072
3073 if (raw_cmd->next &&
3074 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3075 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3076 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3077 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3078 raw_cmd = raw_cmd->next;
3079 return;
3080 }
3081 }
3082 generic_done(flag);
3083}
3084
Stephen Hemminger3b06c212010-07-20 20:09:00 -06003085static const struct cont_t raw_cmd_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086 .interrupt = success_and_wakeup,
3087 .redo = floppy_start,
3088 .error = generic_failure,
3089 .done = raw_cmd_done
3090};
3091
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003092static int raw_cmd_copyout(int cmd, void __user *param,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 struct floppy_raw_cmd *ptr)
3094{
3095 int ret;
3096
3097 while (ptr) {
Joe Perchesce2f11f2010-03-10 15:21:08 -08003098 ret = copy_to_user(param, ptr, sizeof(*ptr));
Joe Perches86b12b42010-03-10 15:20:56 -08003099 if (ret)
3100 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 param += sizeof(struct floppy_raw_cmd);
3102 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003103 if (ptr->length >= 0 &&
3104 ptr->length <= ptr->buffer_length) {
3105 long length = ptr->buffer_length - ptr->length;
Joe Perches4575b552010-03-10 15:20:55 -08003106 ret = fd_copyout(ptr->data, ptr->kernel_data,
3107 length);
3108 if (ret)
3109 return ret;
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003110 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 }
3112 ptr = ptr->next;
3113 }
Joe Perches7f252712010-03-10 15:21:08 -08003114
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115 return 0;
3116}
3117
3118static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3119{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003120 struct floppy_raw_cmd *next;
3121 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122
3123 this = *ptr;
3124 *ptr = NULL;
3125 while (this) {
3126 if (this->buffer_length) {
3127 fd_dma_mem_free((unsigned long)this->kernel_data,
3128 this->buffer_length);
3129 this->buffer_length = 0;
3130 }
3131 next = this->next;
3132 kfree(this);
3133 this = next;
3134 }
3135}
3136
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003137static int raw_cmd_copyin(int cmd, void __user *param,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138 struct floppy_raw_cmd **rcmd)
3139{
3140 struct floppy_raw_cmd *ptr;
3141 int ret;
3142 int i;
3143
3144 *rcmd = NULL;
Joe Perches7f252712010-03-10 15:21:08 -08003145
3146loop:
3147 ptr = kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3148 if (!ptr)
3149 return -ENOMEM;
3150 *rcmd = ptr;
3151 ret = copy_from_user(ptr, param, sizeof(*ptr));
3152 if (ret)
3153 return -EFAULT;
3154 ptr->next = NULL;
3155 ptr->buffer_length = 0;
3156 param += sizeof(struct floppy_raw_cmd);
3157 if (ptr->cmd_count > 33)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 /* the command may now also take up the space
3159 * initially intended for the reply & the
3160 * reply count. Needed for long 82078 commands
3161 * such as RESTORE, which takes ... 17 command
3162 * bytes. Murphy's law #137: When you reserve
3163 * 16 bytes for a structure, you'll one day
3164 * discover that you really need 17...
3165 */
Joe Perches7f252712010-03-10 15:21:08 -08003166 return -EINVAL;
3167
3168 for (i = 0; i < 16; i++)
3169 ptr->reply[i] = 0;
3170 ptr->resultcode = 0;
3171 ptr->kernel_data = NULL;
3172
3173 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3174 if (ptr->length <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175 return -EINVAL;
Joe Perches7f252712010-03-10 15:21:08 -08003176 ptr->kernel_data = (char *)fd_dma_mem_alloc(ptr->length);
3177 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3178 if (!ptr->kernel_data)
3179 return -ENOMEM;
3180 ptr->buffer_length = ptr->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 }
Joe Perches7f252712010-03-10 15:21:08 -08003182 if (ptr->flags & FD_RAW_WRITE) {
3183 ret = fd_copyin(ptr->data, ptr->kernel_data, ptr->length);
3184 if (ret)
3185 return ret;
3186 }
3187
3188 if (ptr->flags & FD_RAW_MORE) {
3189 rcmd = &(ptr->next);
3190 ptr->rate &= 0x43;
3191 goto loop;
3192 }
3193
3194 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195}
3196
3197static int raw_cmd_ioctl(int cmd, void __user *param)
3198{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003200 int drive;
3201 int ret2;
3202 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203
3204 if (FDCS->rawcmd <= 1)
3205 FDCS->rawcmd = 1;
3206 for (drive = 0; drive < N_DRIVE; drive++) {
3207 if (FDC(drive) != fdc)
3208 continue;
3209 if (drive == current_drive) {
3210 if (UDRS->fd_ref > 1) {
3211 FDCS->rawcmd = 2;
3212 break;
3213 }
3214 } else if (UDRS->fd_ref) {
3215 FDCS->rawcmd = 2;
3216 break;
3217 }
3218 }
3219
3220 if (FDCS->reset)
3221 return -EIO;
3222
3223 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3224 if (ret) {
3225 raw_cmd_free(&my_raw_cmd);
3226 return ret;
3227 }
3228
3229 raw_cmd = my_raw_cmd;
3230 cont = &raw_cmd_cont;
Joe Perches74f63f42010-03-10 15:20:58 -08003231 ret = wait_til_done(floppy_start, true);
Joe Perches87f530d2010-03-10 15:20:54 -08003232 debug_dcl(DP->flags, "calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233
3234 if (ret != -EINTR && FDCS->reset)
3235 ret = -EIO;
3236
3237 DRS->track = NO_TRACK;
3238
3239 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3240 if (!ret)
3241 ret = ret2;
3242 raw_cmd_free(&my_raw_cmd);
3243 return ret;
3244}
3245
3246static int invalidate_drive(struct block_device *bdev)
3247{
3248 /* invalidate the buffer track to force a reread */
3249 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3250 process_fd_request();
3251 check_disk_change(bdev);
3252 return 0;
3253}
3254
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003255static int set_geometry(unsigned int cmd, struct floppy_struct *g,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 int drive, int type, struct block_device *bdev)
3257{
3258 int cnt;
3259
3260 /* sanity checking for parameters. */
3261 if (g->sect <= 0 ||
3262 g->head <= 0 ||
3263 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3264 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003265 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 return -EINVAL;
3267 if (type) {
3268 if (!capable(CAP_SYS_ADMIN))
3269 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003270 mutex_lock(&open_lock);
Joe Perches74f63f42010-03-10 15:20:58 -08003271 if (lock_fdc(drive, true)) {
Jiri Slaby8516a502009-06-30 11:41:44 -07003272 mutex_unlock(&open_lock);
3273 return -EINTR;
3274 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 floppy_type[type] = *g;
3276 floppy_type[type].name = "user format";
3277 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3278 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3279 floppy_type[type].size + 1;
3280 process_fd_request();
3281 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3282 struct block_device *bdev = opened_bdev[cnt];
3283 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3284 continue;
NeilBrown93b270f2011-02-24 17:25:47 +11003285 __invalidate_device(bdev, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003287 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 } else {
3289 int oldStretch;
Joe Perches52a0d612010-03-10 15:20:53 -08003290
Joe Perches74f63f42010-03-10 15:20:58 -08003291 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003292 return -EINTR;
Joe Perches4575b552010-03-10 15:20:55 -08003293 if (cmd != FDDEFPRM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 /* notice a disk change immediately, else
3295 * we lose our settings immediately*/
Joe Perches74f63f42010-03-10 15:20:58 -08003296 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003297 return -EINTR;
3298 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299 oldStretch = g->stretch;
3300 user_params[drive] = *g;
3301 if (buffer_drive == drive)
3302 SUPBOUND(buffer_max, user_params[drive].sect);
3303 current_type[drive] = &user_params[drive];
3304 floppy_sizes[drive] = user_params[drive].size;
3305 if (cmd == FDDEFPRM)
3306 DRS->keep_data = -1;
3307 else
3308 DRS->keep_data = 1;
3309 /* invalidation. Invalidate only when needed, i.e.
3310 * when there are already sectors in the buffer cache
3311 * whose number will change. This is useful, because
3312 * mtools often changes the geometry of the disk after
3313 * looking at the boot block */
3314 if (DRS->maxblock > user_params[drive].sect ||
3315 DRS->maxtrack ||
3316 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003317 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 invalidate_drive(bdev);
3319 else
3320 process_fd_request();
3321 }
3322 return 0;
3323}
3324
3325/* handle obsolete ioctl's */
Stephen Hemminger21af5442010-06-15 13:21:11 +02003326static unsigned int ioctl_table[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 FDCLRPRM,
3328 FDSETPRM,
3329 FDDEFPRM,
3330 FDGETPRM,
3331 FDMSGON,
3332 FDMSGOFF,
3333 FDFMTBEG,
3334 FDFMTTRK,
3335 FDFMTEND,
3336 FDSETEMSGTRESH,
3337 FDFLUSH,
3338 FDSETMAXERRS,
3339 FDGETMAXERRS,
3340 FDGETDRVTYP,
3341 FDSETDRVPRM,
3342 FDGETDRVPRM,
3343 FDGETDRVSTAT,
3344 FDPOLLDRVSTAT,
3345 FDRESET,
3346 FDGETFDCSTAT,
3347 FDWERRORCLR,
3348 FDWERRORGET,
3349 FDRAWCMD,
3350 FDEJECT,
3351 FDTWADDLE
3352};
3353
Stephen Hemminger21af5442010-06-15 13:21:11 +02003354static int normalize_ioctl(unsigned int *cmd, int *size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355{
3356 int i;
3357
3358 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3359 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3360 *size = _IOC_SIZE(*cmd);
3361 *cmd = ioctl_table[i];
3362 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003363 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 return -EFAULT;
3365 }
3366 return 0;
3367 }
3368 }
3369 return -EINVAL;
3370}
3371
3372static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3373{
3374 if (type)
3375 *g = &floppy_type[type];
3376 else {
Joe Perches74f63f42010-03-10 15:20:58 -08003377 if (lock_fdc(drive, false))
Joe Perches52a0d612010-03-10 15:20:53 -08003378 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003379 if (poll_drive(false, 0) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003380 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 process_fd_request();
3382 *g = current_type[drive];
3383 }
3384 if (!*g)
3385 return -ENODEV;
3386 return 0;
3387}
3388
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003389static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3390{
3391 int drive = (long)bdev->bd_disk->private_data;
3392 int type = ITYPE(drive_state[drive].fd_device);
3393 struct floppy_struct *g;
3394 int ret;
3395
3396 ret = get_floppy_geometry(drive, type, &g);
3397 if (ret)
3398 return ret;
3399
3400 geo->heads = g->head;
3401 geo->sectors = g->sect;
3402 geo->cylinders = g->track;
3403 return 0;
3404}
3405
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003406static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 unsigned long param)
3408{
Al Viroa4af9b42008-03-02 09:27:55 -05003409 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003410 int type = ITYPE(UDRS->fd_device);
3411 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 int ret;
3413 int size;
3414 union inparam {
3415 struct floppy_struct g; /* geometry */
3416 struct format_descr f;
3417 struct floppy_max_errors max_errors;
3418 struct floppy_drive_params dp;
3419 } inparam; /* parameters coming from user space */
Joe Perches724ee622010-03-10 15:21:11 -08003420 const void *outparam; /* parameters passed back to user space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421
3422 /* convert compatibility eject ioctls into floppy eject ioctl.
3423 * We do this in order to provide a means to eject floppy disks before
3424 * installing the new fdutils package */
3425 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003426 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 DPRINT("obsolete eject ioctl\n");
3428 DPRINT("please use floppycontrol --eject\n");
3429 cmd = FDEJECT;
3430 }
3431
Joe Perchesa81ee542010-03-10 15:20:46 -08003432 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 return -EINVAL;
3434
Joe Perchesa81ee542010-03-10 15:20:46 -08003435 /* convert the old style command into a new style command */
Joe Perches4575b552010-03-10 15:20:55 -08003436 ret = normalize_ioctl(&cmd, &size);
3437 if (ret)
3438 return ret;
Joe Perchesa81ee542010-03-10 15:20:46 -08003439
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 /* permission checks */
Joe Perches0aad92c2010-03-10 15:21:10 -08003441 if (((cmd & 0x40) && !(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL))) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3443 return -EPERM;
3444
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003445 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3446 return -EINVAL;
3447
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 /* copyin */
Joe Perchesb87c9e02010-03-10 15:20:50 -08003449 memset(&inparam, 0, sizeof(inparam));
Joe Perches4575b552010-03-10 15:20:55 -08003450 if (_IOC_DIR(cmd) & _IOC_WRITE) {
3451 ret = fd_copyin((void __user *)param, &inparam, size);
3452 if (ret)
3453 return ret;
3454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455
Joe Perchesda273652010-03-10 15:20:52 -08003456 switch (cmd) {
3457 case FDEJECT:
3458 if (UDRS->fd_ref != 1)
3459 /* somebody else has this drive open */
3460 return -EBUSY;
Joe Perches74f63f42010-03-10 15:20:58 -08003461 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003462 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463
Joe Perchesda273652010-03-10 15:20:52 -08003464 /* do the actual eject. Fails on
3465 * non-Sparc architectures */
3466 ret = fd_eject(UNIT(drive));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467
Joe Perchese0298532010-03-10 15:20:55 -08003468 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3469 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Joe Perchesda273652010-03-10 15:20:52 -08003470 process_fd_request();
3471 return ret;
3472 case FDCLRPRM:
Joe Perches74f63f42010-03-10 15:20:58 -08003473 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003474 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003475 current_type[drive] = NULL;
3476 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3477 UDRS->keep_data = 0;
3478 return invalidate_drive(bdev);
3479 case FDSETPRM:
3480 case FDDEFPRM:
3481 return set_geometry(cmd, &inparam.g, drive, type, bdev);
3482 case FDGETPRM:
Joe Perches4575b552010-03-10 15:20:55 -08003483 ret = get_floppy_geometry(drive, type,
Joe Perches724ee622010-03-10 15:21:11 -08003484 (struct floppy_struct **)&outparam);
Joe Perches4575b552010-03-10 15:20:55 -08003485 if (ret)
3486 return ret;
Joe Perchesda273652010-03-10 15:20:52 -08003487 break;
3488 case FDMSGON:
3489 UDP->flags |= FTD_MSG;
3490 return 0;
3491 case FDMSGOFF:
3492 UDP->flags &= ~FTD_MSG;
3493 return 0;
3494 case FDFMTBEG:
Joe Perches74f63f42010-03-10 15:20:58 -08003495 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003496 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003497 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003498 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003499 ret = UDRS->flags;
3500 process_fd_request();
3501 if (ret & FD_VERIFY)
3502 return -ENODEV;
3503 if (!(ret & FD_DISK_WRITABLE))
3504 return -EROFS;
3505 return 0;
3506 case FDFMTTRK:
3507 if (UDRS->fd_ref != 1)
3508 return -EBUSY;
3509 return do_format(drive, &inparam.f);
3510 case FDFMTEND:
3511 case FDFLUSH:
Joe Perches74f63f42010-03-10 15:20:58 -08003512 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003513 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003514 return invalidate_drive(bdev);
3515 case FDSETEMSGTRESH:
3516 UDP->max_errors.reporting = (unsigned short)(param & 0x0f);
3517 return 0;
3518 case FDGETMAXERRS:
Joe Perches724ee622010-03-10 15:21:11 -08003519 outparam = &UDP->max_errors;
Joe Perchesda273652010-03-10 15:20:52 -08003520 break;
3521 case FDSETMAXERRS:
3522 UDP->max_errors = inparam.max_errors;
3523 break;
3524 case FDGETDRVTYP:
3525 outparam = drive_name(type, drive);
Joe Perches724ee622010-03-10 15:21:11 -08003526 SUPBOUND(size, strlen((const char *)outparam) + 1);
Joe Perchesda273652010-03-10 15:20:52 -08003527 break;
3528 case FDSETDRVPRM:
3529 *UDP = inparam.dp;
3530 break;
3531 case FDGETDRVPRM:
Joe Perches724ee622010-03-10 15:21:11 -08003532 outparam = UDP;
Joe Perchesda273652010-03-10 15:20:52 -08003533 break;
3534 case FDPOLLDRVSTAT:
Joe Perches74f63f42010-03-10 15:20:58 -08003535 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003536 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003537 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003538 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003539 process_fd_request();
3540 /* fall through */
3541 case FDGETDRVSTAT:
Joe Perches724ee622010-03-10 15:21:11 -08003542 outparam = UDRS;
Joe Perchesda273652010-03-10 15:20:52 -08003543 break;
3544 case FDRESET:
Joe Perches74f63f42010-03-10 15:20:58 -08003545 return user_reset_fdc(drive, (int)param, true);
Joe Perchesda273652010-03-10 15:20:52 -08003546 case FDGETFDCSTAT:
Joe Perches724ee622010-03-10 15:21:11 -08003547 outparam = UFDCS;
Joe Perchesda273652010-03-10 15:20:52 -08003548 break;
3549 case FDWERRORCLR:
3550 memset(UDRWE, 0, sizeof(*UDRWE));
3551 return 0;
3552 case FDWERRORGET:
Joe Perches724ee622010-03-10 15:21:11 -08003553 outparam = UDRWE;
Joe Perchesda273652010-03-10 15:20:52 -08003554 break;
3555 case FDRAWCMD:
3556 if (type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 return -EINVAL;
Joe Perches74f63f42010-03-10 15:20:58 -08003558 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003559 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003560 set_floppy(drive);
Joe Perches4575b552010-03-10 15:20:55 -08003561 i = raw_cmd_ioctl(cmd, (void __user *)param);
3562 if (i == -EINTR)
3563 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003564 process_fd_request();
3565 return i;
3566 case FDTWADDLE:
Joe Perches74f63f42010-03-10 15:20:58 -08003567 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003568 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003569 twaddle();
3570 process_fd_request();
3571 return 0;
3572 default:
3573 return -EINVAL;
3574 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575
3576 if (_IOC_DIR(cmd) & _IOC_READ)
3577 return fd_copyout((void __user *)param, outparam, size);
Joe Perchesda273652010-03-10 15:20:52 -08003578
3579 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580}
3581
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003582static int fd_ioctl(struct block_device *bdev, fmode_t mode,
3583 unsigned int cmd, unsigned long param)
3584{
3585 int ret;
3586
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003587 mutex_lock(&floppy_mutex);
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003588 ret = fd_locked_ioctl(bdev, mode, cmd, param);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003589 mutex_unlock(&floppy_mutex);
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003590
3591 return ret;
3592}
3593
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594static void __init config_types(void)
3595{
Joe Perchesb46df352010-03-10 15:20:46 -08003596 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 int drive;
3598
3599 /* read drive info out of physical CMOS */
3600 drive = 0;
3601 if (!UDP->cmos)
3602 UDP->cmos = FLOPPY0_TYPE;
3603 drive = 1;
3604 if (!UDP->cmos && FLOPPY1_TYPE)
3605 UDP->cmos = FLOPPY1_TYPE;
3606
Jesper Juhl06f748c2007-10-16 23:30:57 -07003607 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608
3609 for (drive = 0; drive < N_DRIVE; drive++) {
3610 unsigned int type = UDP->cmos;
3611 struct floppy_drive_params *params;
3612 const char *name = NULL;
3613 static char temparea[32];
3614
Tobias Klauser945f3902006-01-08 01:05:11 -08003615 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 params = &default_drive_params[type].params;
3617 if (type) {
3618 name = default_drive_params[type].name;
3619 allowed_drive_mask |= 1 << drive;
3620 } else
3621 allowed_drive_mask &= ~(1 << drive);
3622 } else {
3623 params = &default_drive_params[0].params;
3624 sprintf(temparea, "unknown type %d (usb?)", type);
3625 name = temparea;
3626 }
3627 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003628 const char *prepend;
3629 if (!has_drive) {
3630 prepend = "";
3631 has_drive = true;
3632 pr_info("Floppy drive(s):");
3633 } else {
3634 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 }
Joe Perchesb46df352010-03-10 15:20:46 -08003636
3637 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 }
3639 *UDP = *params;
3640 }
Joe Perchesb46df352010-03-10 15:20:46 -08003641
3642 if (has_drive)
3643 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644}
3645
Al Viroa4af9b42008-03-02 09:27:55 -05003646static int floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647{
Al Viroa4af9b42008-03-02 09:27:55 -05003648 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003650 mutex_lock(&floppy_mutex);
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003651 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 if (UDRS->fd_ref < 0)
3653 UDRS->fd_ref = 0;
3654 else if (!UDRS->fd_ref--) {
3655 DPRINT("floppy_release with fd_ref == 0");
3656 UDRS->fd_ref = 0;
3657 }
3658 if (!UDRS->fd_ref)
3659 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003660 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003661 mutex_unlock(&floppy_mutex);
Ingo Molnar3e541a42006-07-03 00:24:23 -07003662
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 return 0;
3664}
3665
3666/*
3667 * floppy_open check for aliasing (/dev/fd0 can be the same as
3668 * /dev/PS0 etc), and disallows simultaneous access to the same
3669 * drive with different device numbers.
3670 */
Al Viroa4af9b42008-03-02 09:27:55 -05003671static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672{
Al Viroa4af9b42008-03-02 09:27:55 -05003673 int drive = (long)bdev->bd_disk->private_data;
3674 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675 int try;
3676 int res = -EBUSY;
3677 char *tmp;
3678
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003679 mutex_lock(&floppy_mutex);
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003680 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003682 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 goto out2;
3684
3685 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
Joe Perchese0298532010-03-10 15:20:55 -08003686 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3687 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 }
3689
Al Viroa4af9b42008-03-02 09:27:55 -05003690 if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691 goto out2;
3692
Al Viroa4af9b42008-03-02 09:27:55 -05003693 if (mode & FMODE_EXCL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 UDRS->fd_ref = -1;
3695 else
3696 UDRS->fd_ref++;
3697
Al Viroa4af9b42008-03-02 09:27:55 -05003698 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699
3700 res = -ENXIO;
3701
3702 if (!floppy_track_buffer) {
3703 /* if opening an ED drive, reserve a big buffer,
3704 * else reserve a small one */
3705 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3706 try = 64; /* Only 48 actually useful */
3707 else
3708 try = 32; /* Only 24 actually useful */
3709
3710 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3711 if (!tmp && !floppy_track_buffer) {
3712 try >>= 1; /* buffer only one side */
3713 INFBOUND(try, 16);
3714 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3715 }
Joe Perchesa81ee542010-03-10 15:20:46 -08003716 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 if (!tmp && !floppy_track_buffer) {
3719 DPRINT("Unable to allocate DMA memory\n");
3720 goto out;
3721 }
3722 if (floppy_track_buffer) {
3723 if (tmp)
3724 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3725 } else {
3726 buffer_min = buffer_max = -1;
3727 floppy_track_buffer = tmp;
3728 max_buffer_sectors = try;
3729 }
3730 }
3731
Al Viroa4af9b42008-03-02 09:27:55 -05003732 new_dev = MINOR(bdev->bd_dev);
3733 UDRS->fd_device = new_dev;
3734 set_capacity(disks[drive], floppy_sizes[new_dev]);
3735 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 if (buffer_drive == drive)
3737 buffer_track = -1;
3738 }
3739
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740 if (UFDCS->rawcmd == 1)
3741 UFDCS->rawcmd = 2;
3742
Al Viroa4af9b42008-03-02 09:27:55 -05003743 if (!(mode & FMODE_NDELAY)) {
3744 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745 UDRS->last_checked = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003746 check_disk_change(bdev);
Joe Perchese0298532010-03-10 15:20:55 -08003747 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748 goto out;
3749 }
3750 res = -EROFS;
Joe Perchese0298532010-03-10 15:20:55 -08003751 if ((mode & FMODE_WRITE) &&
3752 !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753 goto out;
3754 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003755 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003756 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 return 0;
3758out:
3759 if (UDRS->fd_ref < 0)
3760 UDRS->fd_ref = 0;
3761 else
3762 UDRS->fd_ref--;
3763 if (!UDRS->fd_ref)
3764 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003766 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003767 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 return res;
3769}
3770
3771/*
3772 * Check if the disk has been changed or if a change has been faked.
3773 */
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003774static unsigned int floppy_check_events(struct gendisk *disk,
3775 unsigned int clearing)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776{
3777 int drive = (long)disk->private_data;
3778
Joe Perchese0298532010-03-10 15:20:55 -08003779 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3780 test_bit(FD_VERIFY_BIT, &UDRS->flags))
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003781 return DISK_EVENT_MEDIA_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003783 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Joe Perches74f63f42010-03-10 15:20:58 -08003784 lock_fdc(drive, false);
3785 poll_drive(false, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 }
3788
Joe Perchese0298532010-03-10 15:20:55 -08003789 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3790 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 test_bit(drive, &fake_change) ||
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003792 drive_no_geom(drive))
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003793 return DISK_EVENT_MEDIA_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 return 0;
3795}
3796
3797/*
3798 * This implements "read block 0" for floppy_revalidate().
3799 * Needed for format autodetection, checking whether there is
3800 * a disk in the drive, and whether that disk is writable.
3801 */
3802
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003803static void floppy_rb0_complete(struct bio *bio, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805 complete((struct completion *)bio->bi_private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806}
3807
3808static int __floppy_read_block_0(struct block_device *bdev)
3809{
3810 struct bio bio;
3811 struct bio_vec bio_vec;
3812 struct completion complete;
3813 struct page *page;
3814 size_t size;
3815
3816 page = alloc_page(GFP_NOIO);
3817 if (!page) {
3818 process_fd_request();
3819 return -ENOMEM;
3820 }
3821
3822 size = bdev->bd_block_size;
3823 if (!size)
3824 size = 1024;
3825
3826 bio_init(&bio);
3827 bio.bi_io_vec = &bio_vec;
3828 bio_vec.bv_page = page;
3829 bio_vec.bv_len = size;
3830 bio_vec.bv_offset = 0;
3831 bio.bi_vcnt = 1;
3832 bio.bi_idx = 0;
3833 bio.bi_size = size;
3834 bio.bi_bdev = bdev;
3835 bio.bi_sector = 0;
Stephen Hemminger41a55b42010-06-15 13:21:11 +02003836 bio.bi_flags = BIO_QUIET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837 init_completion(&complete);
3838 bio.bi_private = &complete;
3839 bio.bi_end_io = floppy_rb0_complete;
3840
3841 submit_bio(READ, &bio);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842 process_fd_request();
3843 wait_for_completion(&complete);
3844
3845 __free_page(page);
3846
3847 return 0;
3848}
3849
3850/* revalidate the floppy disk, i.e. trigger format autodetection by reading
3851 * the bootblock (block 0). "Autodetection" is also needed to check whether
3852 * there is a disk in the drive at all... Thus we also do it for fixed
3853 * geometry formats */
3854static int floppy_revalidate(struct gendisk *disk)
3855{
3856 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 int cf;
3858 int res = 0;
3859
Joe Perchese0298532010-03-10 15:20:55 -08003860 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3861 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003862 test_bit(drive, &fake_change) ||
3863 drive_no_geom(drive)) {
Stephen Hemminger01b6b672010-06-15 13:21:11 +02003864 if (WARN(atomic_read(&usage_count) == 0,
3865 "VFS: revalidate called on non-open device.\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866 return -EFAULT;
Stephen Hemminger01b6b672010-06-15 13:21:11 +02003867
Joe Perches74f63f42010-03-10 15:20:58 -08003868 lock_fdc(drive, false);
Joe Perchese0298532010-03-10 15:20:55 -08003869 cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3870 test_bit(FD_VERIFY_BIT, &UDRS->flags));
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003871 if (!(cf || test_bit(drive, &fake_change) || drive_no_geom(drive))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 process_fd_request(); /*already done by another thread */
3873 return 0;
3874 }
3875 UDRS->maxblock = 0;
3876 UDRS->maxtrack = 0;
3877 if (buffer_drive == drive)
3878 buffer_track = -1;
3879 clear_bit(drive, &fake_change);
Joe Perchese0298532010-03-10 15:20:55 -08003880 clear_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 if (cf)
3882 UDRS->generation++;
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003883 if (drive_no_geom(drive)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 /* auto-sensing */
3885 res = __floppy_read_block_0(opened_bdev[drive]);
3886 } else {
3887 if (cf)
Joe Perches74f63f42010-03-10 15:20:58 -08003888 poll_drive(false, FD_RAW_NEED_DISK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889 process_fd_request();
3890 }
3891 }
3892 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
3893 return res;
3894}
3895
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07003896static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07003897 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05003898 .open = floppy_open,
3899 .release = floppy_release,
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003900 .ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003901 .getgeo = fd_getgeo,
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003902 .check_events = floppy_check_events,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003903 .revalidate_disk = floppy_revalidate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906/*
3907 * Floppy Driver initialization
3908 * =============================
3909 */
3910
3911/* Determine the floppy disk controller type */
3912/* This routine was written by David C. Niemi */
3913static char __init get_fdc_version(void)
3914{
3915 int r;
3916
3917 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
3918 if (FDCS->reset)
3919 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003920 r = result();
3921 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922 return FDC_NONE; /* No FDC present ??? */
3923 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003924 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3926 }
3927 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003928 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3929 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930 return FDC_UNKNOWN;
3931 }
3932
3933 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003934 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3936 }
3937
3938 output_byte(FD_PERPENDICULAR);
3939 if (need_more_output() == MORE_OUTPUT) {
3940 output_byte(0);
3941 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003942 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003943 return FDC_82072A; /* 82072A as found on Sparcs. */
3944 }
3945
3946 output_byte(FD_UNLOCK);
3947 r = result();
3948 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003949 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003950 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07003951 * LOCK/UNLOCK */
3952 }
3953 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003954 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3955 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 return FDC_UNKNOWN;
3957 }
3958 output_byte(FD_PARTID);
3959 r = result();
3960 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003961 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3962 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963 return FDC_UNKNOWN;
3964 }
3965 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003966 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 return FDC_82077; /* Revised 82077AA passes all the tests */
3968 }
3969 switch (reply_buffer[0] >> 5) {
3970 case 0x0:
3971 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08003972 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973 return FDC_82078;
3974 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08003975 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976 return FDC_82078;
3977 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08003978 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 return FDC_S82078B;
3980 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08003981 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982 return FDC_87306;
3983 default:
Joe Perchesb46df352010-03-10 15:20:46 -08003984 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
3985 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986 return FDC_82078_UNKN;
3987 }
3988} /* get_fdc_version */
3989
3990/* lilo configuration */
3991
3992static void __init floppy_set_flags(int *ints, int param, int param2)
3993{
3994 int i;
3995
3996 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
3997 if (param)
3998 default_drive_params[i].params.flags |= param2;
3999 else
4000 default_drive_params[i].params.flags &= ~param2;
4001 }
4002 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
4003}
4004
4005static void __init daring(int *ints, int param, int param2)
4006{
4007 int i;
4008
4009 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4010 if (param) {
4011 default_drive_params[i].params.select_delay = 0;
4012 default_drive_params[i].params.flags |=
4013 FD_SILENT_DCL_CLEAR;
4014 } else {
4015 default_drive_params[i].params.select_delay =
4016 2 * HZ / 100;
4017 default_drive_params[i].params.flags &=
4018 ~FD_SILENT_DCL_CLEAR;
4019 }
4020 }
4021 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
4022}
4023
4024static void __init set_cmos(int *ints, int dummy, int dummy2)
4025{
4026 int current_drive = 0;
4027
4028 if (ints[0] != 2) {
4029 DPRINT("wrong number of parameters for CMOS\n");
4030 return;
4031 }
4032 current_drive = ints[1];
4033 if (current_drive < 0 || current_drive >= 8) {
4034 DPRINT("bad drive for set_cmos\n");
4035 return;
4036 }
4037#if N_FDC > 1
4038 if (current_drive >= 4 && !FDC2)
4039 FDC2 = 0x370;
4040#endif
4041 DP->cmos = ints[2];
4042 DPRINT("setting CMOS code to %d\n", ints[2]);
4043}
4044
4045static struct param_table {
4046 const char *name;
4047 void (*fn) (int *ints, int param, int param2);
4048 int *var;
4049 int def_param;
4050 int param2;
4051} config_params[] __initdata = {
4052 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4053 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4054 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4055 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4056 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4057 {"daring", daring, NULL, 1, 0},
4058#if N_FDC > 1
4059 {"two_fdc", NULL, &FDC2, 0x370, 0},
4060 {"one_fdc", NULL, &FDC2, 0, 0},
4061#endif
4062 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4063 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4064 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4065 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4066 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4067 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4068 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4069 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4070 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4071 {"nofifo", NULL, &no_fifo, 0x20, 0},
4072 {"usefifo", NULL, &no_fifo, 0, 0},
4073 {"cmos", set_cmos, NULL, 0, 0},
4074 {"slow", NULL, &slow_floppy, 1, 0},
4075 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4076 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4077 {"L40SX", NULL, &print_unex, 0, 0}
4078
4079 EXTRA_FLOPPY_PARAMS
4080};
4081
4082static int __init floppy_setup(char *str)
4083{
4084 int i;
4085 int param;
4086 int ints[11];
4087
4088 str = get_options(str, ARRAY_SIZE(ints), ints);
4089 if (str) {
4090 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4091 if (strcmp(str, config_params[i].name) == 0) {
4092 if (ints[0])
4093 param = ints[1];
4094 else
4095 param = config_params[i].def_param;
4096 if (config_params[i].fn)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004097 config_params[i].fn(ints, param,
4098 config_params[i].
4099 param2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100 if (config_params[i].var) {
4101 DPRINT("%s=%d\n", str, param);
4102 *config_params[i].var = param;
4103 }
4104 return 1;
4105 }
4106 }
4107 }
4108 if (str) {
4109 DPRINT("unknown floppy option [%s]\n", str);
4110
4111 DPRINT("allowed options are:");
4112 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004113 pr_cont(" %s", config_params[i].name);
4114 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115 } else
4116 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004117 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118 return 0;
4119}
4120
4121static int have_no_fdc = -ENODEV;
4122
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004123static ssize_t floppy_cmos_show(struct device *dev,
4124 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004125{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004126 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004127 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004128
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004129 drive = p->id;
4130 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004131}
Joe Perches48c8cee2010-03-10 15:20:45 -08004132
Stephen Hemmingerbe1c0fb2010-06-15 13:21:11 +02004133static DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004134
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135static void floppy_device_release(struct device *dev)
4136{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137}
4138
Frans Popc90cd332009-07-25 22:24:54 +02004139static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004140{
4141 int fdc;
4142
4143 for (fdc = 0; fdc < N_FDC; fdc++)
4144 if (FDCS->address != -1)
Joe Perches74f63f42010-03-10 15:20:58 -08004145 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004146
4147 return 0;
4148}
4149
Alexey Dobriyan47145212009-12-14 18:00:08 -08004150static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004151 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004152 .restore = floppy_resume,
4153};
4154
4155static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004156 .driver = {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004157 .name = "floppy",
4158 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004159 },
4160};
4161
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004162static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163
4164static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4165{
4166 int drive = (*part & 3) | ((*part & 0x80) >> 5);
4167 if (drive >= N_DRIVE ||
4168 !(allowed_drive_mask & (1 << drive)) ||
4169 fdc_state[FDC(drive)].version == FDC_NONE)
4170 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004171 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172 return NULL;
4173 *part = 0;
4174 return get_disk(disks[drive]);
4175}
4176
4177static int __init floppy_init(void)
4178{
4179 int i, unit, drive;
4180 int err, dr;
4181
Stephen Hemminger285203c2010-06-15 13:21:11 +02004182 set_debugt();
4183 interruptjiffies = resultjiffies = jiffies;
4184
Kumar Gala68e1ee62008-09-22 14:41:31 -07004185#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004186 if (check_legacy_ioport(FDC1))
4187 return -ENODEV;
4188#endif
4189
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 raw_cmd = NULL;
4191
4192 for (dr = 0; dr < N_DRIVE; dr++) {
4193 disks[dr] = alloc_disk(1);
4194 if (!disks[dr]) {
4195 err = -ENOMEM;
4196 goto out_put_disk;
4197 }
4198
Jens Axboe48821182010-09-22 09:32:36 +02004199 disks[dr]->queue = blk_init_queue(do_fd_request, &floppy_lock);
4200 if (!disks[dr]->queue) {
4201 err = -ENOMEM;
4202 goto out_put_disk;
4203 }
4204
4205 blk_queue_max_hw_sectors(disks[dr]->queue, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 disks[dr]->major = FLOPPY_MAJOR;
4207 disks[dr]->first_minor = TOMINOR(dr);
4208 disks[dr]->fops = &floppy_fops;
4209 sprintf(disks[dr]->disk_name, "fd%d", dr);
4210
4211 init_timer(&motor_off_timer[dr]);
4212 motor_off_timer[dr].data = dr;
4213 motor_off_timer[dr].function = motor_off_callback;
4214 }
4215
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216 err = register_blkdev(FLOPPY_MAJOR, "fd");
4217 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004218 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004220 err = platform_driver_register(&floppy_driver);
4221 if (err)
4222 goto out_unreg_blkdev;
4223
Linus Torvalds1da177e2005-04-16 15:20:36 -07004224 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4225 floppy_find, NULL, NULL);
4226
4227 for (i = 0; i < 256; i++)
4228 if (ITYPE(i))
4229 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4230 else
4231 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4232
Joe Perches73507e62010-03-10 15:21:03 -08004233 reschedule_timeout(MAXTIMEOUT, "floppy init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 config_types();
4235
4236 for (i = 0; i < N_FDC; i++) {
4237 fdc = i;
Joe Perchesb87c9e02010-03-10 15:20:50 -08004238 memset(FDCS, 0, sizeof(*FDCS));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239 FDCS->dtr = -1;
4240 FDCS->dor = 0x4;
4241#if defined(__sparc__) || defined(__mc68000__)
Joe Perches96534f12010-03-10 15:20:51 -08004242 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243#ifdef __mc68000__
4244 if (MACH_IS_SUN3X)
4245#endif
4246 FDCS->version = FDC_82072A;
4247#endif
4248 }
4249
4250 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251 fdc_state[0].address = FDC1;
4252 if (fdc_state[0].address == -1) {
4253 del_timer(&fd_timeout);
4254 err = -ENODEV;
4255 goto out_unreg_region;
4256 }
4257#if N_FDC > 1
4258 fdc_state[1].address = FDC2;
4259#endif
4260
4261 fdc = 0; /* reset fdc in case of unexpected interrupt */
4262 err = floppy_grab_irq_and_dma();
4263 if (err) {
4264 del_timer(&fd_timeout);
4265 err = -EBUSY;
4266 goto out_unreg_region;
4267 }
4268
4269 /* initialise drive state */
4270 for (drive = 0; drive < N_DRIVE; drive++) {
Joe Perchesb87c9e02010-03-10 15:20:50 -08004271 memset(UDRS, 0, sizeof(*UDRS));
4272 memset(UDRWE, 0, sizeof(*UDRWE));
Joe Perchese0298532010-03-10 15:20:55 -08004273 set_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
4274 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
4275 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276 UDRS->fd_device = -1;
4277 floppy_track_buffer = NULL;
4278 max_buffer_sectors = 0;
4279 }
4280 /*
4281 * Small 10 msec delay to let through any interrupt that
4282 * initialization might have triggered, to not
4283 * confuse detection:
4284 */
4285 msleep(10);
4286
4287 for (i = 0; i < N_FDC; i++) {
4288 fdc = i;
4289 FDCS->driver_version = FD_DRIVER_VERSION;
4290 for (unit = 0; unit < 4; unit++)
4291 FDCS->track[unit] = 0;
4292 if (FDCS->address == -1)
4293 continue;
4294 FDCS->rawcmd = 2;
Joe Perches74f63f42010-03-10 15:20:58 -08004295 if (user_reset_fdc(-1, FD_RESET_ALWAYS, false)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004297 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298 FDCS->address = -1;
4299 FDCS->version = FDC_NONE;
4300 continue;
4301 }
4302 /* Try to determine the floppy controller type */
4303 FDCS->version = get_fdc_version();
4304 if (FDCS->version == FDC_NONE) {
4305 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004306 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307 FDCS->address = -1;
4308 continue;
4309 }
4310 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4311 can_use_virtual_dma = 0;
4312
4313 have_no_fdc = 0;
4314 /* Not all FDCs seem to be able to handle the version command
4315 * properly, so force a reset for the standard FDC clones,
4316 * to avoid interrupt garbage.
4317 */
Joe Perches74f63f42010-03-10 15:20:58 -08004318 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319 }
4320 fdc = 0;
4321 del_timer(&fd_timeout);
4322 current_drive = 0;
Joe Perches29f1c782010-03-10 15:21:00 -08004323 initialized = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324 if (have_no_fdc) {
4325 DPRINT("no floppy controllers found\n");
4326 err = have_no_fdc;
4327 goto out_flush_work;
4328 }
4329
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 for (drive = 0; drive < N_DRIVE; drive++) {
4331 if (!(allowed_drive_mask & (1 << drive)))
4332 continue;
4333 if (fdc_state[FDC(drive)].version == FDC_NONE)
4334 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004335
4336 floppy_device[drive].name = floppy_device_name;
4337 floppy_device[drive].id = drive;
4338 floppy_device[drive].dev.release = floppy_device_release;
4339
4340 err = platform_device_register(&floppy_device[drive]);
4341 if (err)
4342 goto out_flush_work;
4343
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004344 err = device_create_file(&floppy_device[drive].dev,
4345 &dev_attr_cmos);
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004346 if (err)
4347 goto out_unreg_platform_dev;
4348
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 /* to be cleaned up... */
4350 disks[drive]->private_data = (void *)(long)drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004352 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353 add_disk(disks[drive]);
4354 }
4355
4356 return 0;
4357
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004358out_unreg_platform_dev:
4359 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360out_flush_work:
Tejun Heo8aa0f412010-12-24 15:59:06 +01004361 flush_work_sync(&floppy_work);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004362 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363 floppy_release_irq_and_dma();
4364out_unreg_region:
4365 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004366 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367out_unreg_blkdev:
4368 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369out_put_disk:
4370 while (dr--) {
4371 del_timer(&motor_off_timer[dr]);
Jens Axboe48821182010-09-22 09:32:36 +02004372 if (disks[dr]->queue)
4373 blk_cleanup_queue(disks[dr]->queue);
Linus Torvaldsc093ee42010-11-05 17:45:59 -07004374 put_disk(disks[dr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375 }
4376 return err;
4377}
4378
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004379static const struct io_region {
4380 int offset;
4381 int size;
4382} io_regions[] = {
4383 { 2, 1 },
4384 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4385 { 4, 2 },
4386 /* address + 6 is reserved, and may be taken by IDE.
4387 * Unfortunately, Adaptec doesn't know this :-(, */
4388 { 7, 1 },
4389};
4390
4391static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4392{
4393 while (p != io_regions) {
4394 p--;
4395 release_region(FDCS->address + p->offset, p->size);
4396 }
4397}
4398
4399#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4400
4401static int floppy_request_regions(int fdc)
4402{
4403 const struct io_region *p;
4404
4405 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004406 if (!request_region(FDCS->address + p->offset,
4407 p->size, "floppy")) {
4408 DPRINT("Floppy io-port 0x%04lx in use\n",
4409 FDCS->address + p->offset);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004410 floppy_release_allocated_regions(fdc, p);
4411 return -EBUSY;
4412 }
4413 }
4414 return 0;
4415}
4416
4417static void floppy_release_regions(int fdc)
4418{
4419 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4420}
4421
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422static int floppy_grab_irq_and_dma(void)
4423{
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004424 if (atomic_inc_return(&usage_count) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425 return 0;
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004426
4427 /*
4428 * We might have scheduled a free_irq(), wait it to
4429 * drain first:
4430 */
Tejun Heo8aa0f412010-12-24 15:59:06 +01004431 flush_work_sync(&floppy_work);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004432
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433 if (fd_request_irq()) {
4434 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4435 FLOPPY_IRQ);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004436 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 return -1;
4438 }
4439 if (fd_request_dma()) {
4440 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4441 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004442 if (can_use_virtual_dma & 2)
4443 use_virtual_dma = can_use_virtual_dma = 1;
4444 if (!(can_use_virtual_dma & 1)) {
4445 fd_free_irq();
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004446 atomic_dec(&usage_count);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004447 return -1;
4448 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449 }
4450
4451 for (fdc = 0; fdc < N_FDC; fdc++) {
4452 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004453 if (floppy_request_regions(fdc))
4454 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 }
4456 }
4457 for (fdc = 0; fdc < N_FDC; fdc++) {
4458 if (FDCS->address != -1) {
4459 reset_fdc_info(1);
4460 fd_outb(FDCS->dor, FD_DOR);
4461 }
4462 }
4463 fdc = 0;
4464 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4465
4466 for (fdc = 0; fdc < N_FDC; fdc++)
4467 if (FDCS->address != -1)
4468 fd_outb(FDCS->dor, FD_DOR);
4469 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004470 * The driver will try and free resources and relies on us
4471 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472 */
4473 fdc = 0;
4474 irqdma_allocated = 1;
4475 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004476cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 fd_free_irq();
4478 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004479 while (--fdc >= 0)
4480 floppy_release_regions(fdc);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004481 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 return -1;
4483}
4484
4485static void floppy_release_irq_and_dma(void)
4486{
4487 int old_fdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488#ifndef __sparc__
4489 int drive;
4490#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 long tmpsize;
4492 unsigned long tmpaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004494 if (!atomic_dec_and_test(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495 return;
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004496
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497 if (irqdma_allocated) {
4498 fd_disable_dma();
4499 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004500 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 irqdma_allocated = 0;
4502 }
4503 set_dor(0, ~0, 8);
4504#if N_FDC > 1
4505 set_dor(1, ~8, 0);
4506#endif
4507 floppy_enable_hlt();
4508
4509 if (floppy_track_buffer && max_buffer_sectors) {
4510 tmpsize = max_buffer_sectors * 1024;
4511 tmpaddr = (unsigned long)floppy_track_buffer;
4512 floppy_track_buffer = NULL;
4513 max_buffer_sectors = 0;
4514 buffer_min = buffer_max = -1;
4515 fd_dma_mem_free(tmpaddr, tmpsize);
4516 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517#ifndef __sparc__
4518 for (drive = 0; drive < N_FDC * 4; drive++)
4519 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004520 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521#endif
4522
4523 if (timer_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004524 pr_info("floppy timer still active:%s\n", timeout_message);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004526 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004527 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004528 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 old_fdc = fdc;
4530 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004531 if (FDCS->address != -1)
4532 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533 fdc = old_fdc;
4534}
4535
4536#ifdef MODULE
4537
4538static char *floppy;
4539
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540static void __init parse_floppy_cfg_string(char *cfg)
4541{
4542 char *ptr;
4543
4544 while (*cfg) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004545 ptr = cfg;
4546 while (*cfg && *cfg != ' ' && *cfg != '\t')
4547 cfg++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548 if (*cfg) {
4549 *cfg = '\0';
4550 cfg++;
4551 }
4552 if (*ptr)
4553 floppy_setup(ptr);
4554 }
4555}
4556
Jon Schindler7afea3b2008-04-29 00:59:21 -07004557static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558{
4559 if (floppy)
4560 parse_floppy_cfg_string(floppy);
4561 return floppy_init();
4562}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004563module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564
Jon Schindler7afea3b2008-04-29 00:59:21 -07004565static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566{
4567 int drive;
4568
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4570 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004571 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572
4573 for (drive = 0; drive < N_DRIVE; drive++) {
4574 del_timer_sync(&motor_off_timer[drive]);
4575
4576 if ((allowed_drive_mask & (1 << drive)) &&
4577 fdc_state[FDC(drive)].version != FDC_NONE) {
4578 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004579 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4580 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 }
Jens Axboe48821182010-09-22 09:32:36 +02004582 blk_cleanup_queue(disks[drive]->queue);
Vivek Goyald017bf62010-11-06 08:16:05 -04004583 put_disk(disks[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585
4586 del_timer_sync(&fd_timeout);
4587 del_timer_sync(&fd_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004589 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 floppy_release_irq_and_dma();
4591
4592 /* eject disk, if any */
4593 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594}
Joe Perches48c8cee2010-03-10 15:20:45 -08004595
Jon Schindler7afea3b2008-04-29 00:59:21 -07004596module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597
4598module_param(floppy, charp, 0);
4599module_param(FLOPPY_IRQ, int, 0);
4600module_param(FLOPPY_DMA, int, 0);
4601MODULE_AUTHOR("Alain L. Knaff");
4602MODULE_SUPPORTED_DEVICE("fd");
4603MODULE_LICENSE("GPL");
4604
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004605/* This doesn't actually get used other than for module information */
4606static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004607 {"PNP0700", 0},
4608 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004609};
Joe Perches48c8cee2010-03-10 15:20:45 -08004610
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004611MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4612
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613#else
4614
4615__setup("floppy=", floppy_setup);
4616module_init(floppy_init)
4617#endif
4618
4619MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);