blob: aa42e7766c6a3b52035bfeb8756f711025376a4b [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>
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +0200181#include <linux/smp_lock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182#include <linux/string.h>
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800183#include <linux/jiffies.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184#include <linux/fcntl.h>
185#include <linux/delay.h>
186#include <linux/mc146818rtc.h> /* CMOS defines */
187#include <linux/ioport.h>
188#include <linux/interrupt.h>
189#include <linux/init.h>
Russell Kingd052d1b2005-10-29 19:07:23 +0100190#include <linux/platform_device.h>
Scott James Remnant83f9ef42009-04-02 16:56:47 -0700191#include <linux/mod_devicetable.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192#include <linux/buffer_head.h> /* for invalidate_buffers() */
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800193#include <linux/mutex.h>
Joe Perchesd4937542010-03-10 15:20:44 -0800194#include <linux/io.h>
195#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
197/*
198 * PS/2 floppies have much slower step rates than regular floppies.
199 * It's been recommended that take about 1/4 of the default speed
200 * in some more extreme cases.
201 */
202static 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
600#ifndef fd_eject
601static inline int fd_eject(int drive)
602{
603 return -EINVAL;
604}
605#endif
606
607/*
608 * Debugging
609 * =========
610 */
611#ifdef DEBUGT
612static long unsigned debugtimer;
613
614static inline void set_debugt(void)
615{
616 debugtimer = jiffies;
617}
618
Joe Perchesded28632010-03-10 15:21:09 -0800619static inline void debugt(const char *func, const char *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620{
621 if (DP->flags & DEBUGT)
Joe Perchesded28632010-03-10 15:21:09 -0800622 pr_info("%s:%s dtime=%lu\n", func, msg, jiffies - debugtimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623}
624#else
625static inline void set_debugt(void) { }
Joe Perchesded28632010-03-10 15:21:09 -0800626static inline void debugt(const char *func, const char *msg) { }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627#endif /* DEBUGT */
628
Joe Perchesa0a52d62010-03-10 15:20:52 -0800629typedef void (*timeout_fn)(unsigned long);
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700630static DEFINE_TIMER(fd_timeout, floppy_shutdown, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
632static const char *timeout_message;
633
Joe Perches275176b2010-03-10 15:21:06 -0800634static void is_alive(const char *func, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635{
636 /* this routine checks whether the floppy driver is "alive" */
Joe Perchesc5297302010-03-10 15:20:58 -0800637 if (test_bit(0, &fdc_busy) && command_status < 2 &&
638 !timer_pending(&fd_timeout)) {
Joe Perches275176b2010-03-10 15:21:06 -0800639 DPRINT("%s: timeout handler died. %s\n", func, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 }
641}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
Joe Perches48c8cee2010-03-10 15:20:45 -0800643static void (*do_floppy)(void) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645#define OLOGSIZE 20
646
Joe Perches48c8cee2010-03-10 15:20:45 -0800647static void (*lasthandler)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648static unsigned long interruptjiffies;
649static unsigned long resultjiffies;
650static int resultsize;
651static unsigned long lastredo;
652
653static struct output_log {
654 unsigned char data;
655 unsigned char status;
656 unsigned long jiffies;
657} output_log[OLOGSIZE];
658
659static int output_log_pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
661#define current_reqD -1
662#define MAXTIMEOUT -2
663
Joe Perches73507e62010-03-10 15:21:03 -0800664static void __reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665{
666 if (drive == current_reqD)
667 drive = current_drive;
668 del_timer(&fd_timeout);
Eric Sesterhenn / Snakebyte4acb3e22007-05-23 13:58:15 -0700669 if (drive < 0 || drive >= N_DRIVE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 fd_timeout.expires = jiffies + 20UL * HZ;
671 drive = 0;
672 } else
673 fd_timeout.expires = jiffies + UDP->timeout;
674 add_timer(&fd_timeout);
Joe Perchesa81ee5442010-03-10 15:20:46 -0800675 if (UDP->flags & FD_DEBUG)
Joe Perches73507e62010-03-10 15:21:03 -0800676 DPRINT("reschedule timeout %s\n", message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 timeout_message = message;
678}
679
Joe Perches73507e62010-03-10 15:21:03 -0800680static void reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681{
682 unsigned long flags;
683
684 spin_lock_irqsave(&floppy_lock, flags);
Joe Perches73507e62010-03-10 15:21:03 -0800685 __reschedule_timeout(drive, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 spin_unlock_irqrestore(&floppy_lock, flags);
687}
688
Joe Perches48c8cee2010-03-10 15:20:45 -0800689#define INFBOUND(a, b) (a) = max_t(int, a, b)
690#define SUPBOUND(a, b) (a) = min_t(int, a, b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
692/*
693 * Bottom half floppy driver.
694 * ==========================
695 *
696 * This part of the file contains the code talking directly to the hardware,
697 * and also the main service loop (seek-configure-spinup-command)
698 */
699
700/*
701 * disk change.
702 * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
703 * and the last_checked date.
704 *
705 * last_checked is the date of the last check which showed 'no disk change'
706 * FD_DISK_CHANGE is set under two conditions:
707 * 1. The floppy has been changed after some i/o to that floppy already
708 * took place.
709 * 2. No floppy disk is in the drive. This is done in order to ensure that
710 * requests are quickly flushed in case there is no disk in the drive. It
711 * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
712 * the drive.
713 *
714 * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
715 * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
716 * each seek. If a disk is present, the disk change line should also be
717 * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
718 * change line is set, this means either that no disk is in the drive, or
719 * that it has been removed since the last seek.
720 *
721 * This means that we really have a third possibility too:
722 * The floppy has been changed after the last seek.
723 */
724
725static int disk_change(int drive)
726{
727 int fdc = FDC(drive);
Jesper Juhl06f748c2007-10-16 23:30:57 -0700728
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800729 if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 DPRINT("WARNING disk change called early\n");
731 if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
732 (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
733 DPRINT("probing disk change on unselected drive\n");
734 DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
735 (unsigned int)FDCS->dor);
736 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
Joe Perches87f530d2010-03-10 15:20:54 -0800738 debug_dcl(UDP->flags,
739 "checking disk change line for drive %d\n", drive);
740 debug_dcl(UDP->flags, "jiffies=%lu\n", jiffies);
741 debug_dcl(UDP->flags, "disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
742 debug_dcl(UDP->flags, "flags=%lx\n", UDRS->flags);
743
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 if (UDP->flags & FD_BROKEN_DCL)
Joe Perchese0298532010-03-10 15:20:55 -0800745 return test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
Joe Perchese0298532010-03-10 15:20:55 -0800747 set_bit(FD_VERIFY_BIT, &UDRS->flags);
748 /* verify write protection */
749
750 if (UDRS->maxblock) /* mark it changed */
751 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
753 /* invalidate its geometry */
754 if (UDRS->keep_data >= 0) {
755 if ((UDP->flags & FTD_MSG) &&
756 current_type[drive] != NULL)
Joe Perches891eda82010-03-10 15:21:05 -0800757 DPRINT("Disk type is undefined after disk change\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 current_type[drive] = NULL;
759 floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
760 }
761
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 return 1;
763 } else {
764 UDRS->last_checked = jiffies;
Joe Perchese0298532010-03-10 15:20:55 -0800765 clear_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 }
767 return 0;
768}
769
770static inline int is_selected(int dor, int unit)
771{
772 return ((dor & (0x10 << unit)) && (dor & 3) == unit);
773}
774
Joe Perches57584c52010-03-10 15:21:00 -0800775static bool is_ready_state(int status)
776{
777 int state = status & (STATUS_READY | STATUS_DIR | STATUS_DMA);
778 return state == STATUS_READY;
779}
780
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781static int set_dor(int fdc, char mask, char data)
782{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700783 unsigned char unit;
784 unsigned char drive;
785 unsigned char newdor;
786 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
788 if (FDCS->address == -1)
789 return -1;
790
791 olddor = FDCS->dor;
792 newdor = (olddor & mask) | data;
793 if (newdor != olddor) {
794 unit = olddor & 0x3;
795 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
796 drive = REVDRIVE(fdc, unit);
Joe Perches87f530d2010-03-10 15:20:54 -0800797 debug_dcl(UDP->flags,
798 "calling disk change from set_dor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 disk_change(drive);
800 }
801 FDCS->dor = newdor;
802 fd_outb(newdor, FD_DOR);
803
804 unit = newdor & 0x3;
805 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
806 drive = REVDRIVE(fdc, unit);
807 UDRS->select_date = jiffies;
808 }
809 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 return olddor;
811}
812
813static void twaddle(void)
814{
815 if (DP->select_delay)
816 return;
817 fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
818 fd_outb(FDCS->dor, FD_DOR);
819 DRS->select_date = jiffies;
820}
821
Joe Perches57584c52010-03-10 15:21:00 -0800822/*
823 * Reset all driver information about the current fdc.
824 * This is needed after a reset, and after a raw command.
825 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826static void reset_fdc_info(int mode)
827{
828 int drive;
829
830 FDCS->spec1 = FDCS->spec2 = -1;
831 FDCS->need_configure = 1;
832 FDCS->perp_mode = 1;
833 FDCS->rawcmd = 0;
834 for (drive = 0; drive < N_DRIVE; drive++)
835 if (FDC(drive) == fdc && (mode || UDRS->track != NEED_1_RECAL))
836 UDRS->track = NEED_2_RECAL;
837}
838
839/* selects the fdc and drive, and enables the fdc's input/dma. */
840static void set_fdc(int drive)
841{
842 if (drive >= 0 && drive < N_DRIVE) {
843 fdc = FDC(drive);
844 current_drive = drive;
845 }
846 if (fdc != 1 && fdc != 0) {
Joe Perchesb46df352010-03-10 15:20:46 -0800847 pr_info("bad fdc value\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 return;
849 }
850 set_dor(fdc, ~0, 8);
851#if N_FDC > 1
852 set_dor(1 - fdc, ~8, 0);
853#endif
854 if (FDCS->rawcmd == 2)
855 reset_fdc_info(1);
856 if (fd_inb(FD_STATUS) != STATUS_READY)
857 FDCS->reset = 1;
858}
859
860/* locks the driver */
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200861static int lock_fdc(int drive, bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862{
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200863 if (WARN(atomic_read(&usage_count) == 0,
864 "Trying to lock fdc while usage count=0\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200867 if (wait_event_interruptible(fdc_wait, !test_and_set_bit(0, &fdc_busy)))
868 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 command_status = FD_COMMAND_NONE;
871
Joe Perches73507e62010-03-10 15:21:03 -0800872 __reschedule_timeout(drive, "lock fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 set_fdc(drive);
874 return 0;
875}
876
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877/* unlocks the driver */
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +0200878static void unlock_fdc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879{
880 unsigned long flags;
881
882 raw_cmd = NULL;
883 if (!test_bit(0, &fdc_busy))
884 DPRINT("FDC access conflict!\n");
885
886 if (do_floppy)
Joe Perches1ebddd82010-03-10 15:21:07 -0800887 DPRINT("device interrupt still active at FDC release: %pf!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 do_floppy);
889 command_status = FD_COMMAND_NONE;
890 spin_lock_irqsave(&floppy_lock, flags);
891 del_timer(&fd_timeout);
892 cont = NULL;
893 clear_bit(0, &fdc_busy);
Jens Axboe48821182010-09-22 09:32:36 +0200894 if (current_req || set_next_request())
895 do_fd_request(current_req->q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 spin_unlock_irqrestore(&floppy_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 wake_up(&fdc_wait);
898}
899
900/* switches the motor off after a given timeout */
901static void motor_off_callback(unsigned long nr)
902{
903 unsigned char mask = ~(0x10 << UNIT(nr));
904
905 set_dor(FDC(nr), mask, 0);
906}
907
908/* schedules motor off */
909static void floppy_off(unsigned int drive)
910{
911 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700912 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
914 if (!(FDCS->dor & (0x10 << UNIT(drive))))
915 return;
916
917 del_timer(motor_off_timer + drive);
918
919 /* make spindle stop in a position which minimizes spinup time
920 * next time */
921 if (UDP->rps) {
922 delta = jiffies - UDRS->first_read_date + HZ -
923 UDP->spindown_offset;
924 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
925 motor_off_timer[drive].expires =
926 jiffies + UDP->spindown - delta;
927 }
928 add_timer(motor_off_timer + drive);
929}
930
931/*
932 * cycle through all N_DRIVE floppy drives, for disk change testing.
933 * stopping at current drive. This is done before any long operation, to
934 * be sure to have up to date disk change information.
935 */
936static void scandrives(void)
937{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700938 int i;
939 int drive;
940 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
942 if (DP->select_delay)
943 return;
944
945 saved_drive = current_drive;
946 for (i = 0; i < N_DRIVE; i++) {
947 drive = (saved_drive + i + 1) % N_DRIVE;
948 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
949 continue; /* skip closed drives */
950 set_fdc(drive);
951 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
952 (0x10 << UNIT(drive))))
953 /* switch the motor off again, if it was off to
954 * begin with */
955 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
956 }
957 set_fdc(saved_drive);
958}
959
960static void empty(void)
961{
962}
963
David Howells65f27f32006-11-22 14:55:48 +0000964static DECLARE_WORK(floppy_work, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
Joe Perches48c8cee2010-03-10 15:20:45 -0800966static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967{
David Howells65f27f32006-11-22 14:55:48 +0000968 PREPARE_WORK(&floppy_work, (work_func_t)handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 schedule_work(&floppy_work);
970}
971
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700972static DEFINE_TIMER(fd_timer, NULL, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
974static void cancel_activity(void)
975{
976 unsigned long flags;
977
978 spin_lock_irqsave(&floppy_lock, flags);
979 do_floppy = NULL;
David Howells65f27f32006-11-22 14:55:48 +0000980 PREPARE_WORK(&floppy_work, (work_func_t)empty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 del_timer(&fd_timer);
982 spin_unlock_irqrestore(&floppy_lock, flags);
983}
984
985/* this function makes sure that the disk stays in the drive during the
986 * transfer */
987static void fd_watchdog(void)
988{
Joe Perches87f530d2010-03-10 15:20:54 -0800989 debug_dcl(DP->flags, "calling disk change from watchdog\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
991 if (disk_change(current_drive)) {
992 DPRINT("disk removed during i/o\n");
993 cancel_activity();
994 cont->done(0);
995 reset_fdc();
996 } else {
997 del_timer(&fd_timer);
Joe Perchesa0a52d62010-03-10 15:20:52 -0800998 fd_timer.function = (timeout_fn)fd_watchdog;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 fd_timer.expires = jiffies + HZ / 10;
1000 add_timer(&fd_timer);
1001 }
1002}
1003
1004static void main_command_interrupt(void)
1005{
1006 del_timer(&fd_timer);
1007 cont->interrupt();
1008}
1009
1010/* waits for a delay (spinup or select) to pass */
1011static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
1012{
1013 if (FDCS->reset) {
1014 reset_fdc(); /* do the reset during sleep to win time
1015 * if we don't need to sleep, it's a good
1016 * occasion anyways */
1017 return 1;
1018 }
1019
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001020 if (time_before(jiffies, delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 del_timer(&fd_timer);
1022 fd_timer.function = function;
1023 fd_timer.expires = delay;
1024 add_timer(&fd_timer);
1025 return 1;
1026 }
1027 return 0;
1028}
1029
1030static DEFINE_SPINLOCK(floppy_hlt_lock);
1031static int hlt_disabled;
1032static void floppy_disable_hlt(void)
1033{
1034 unsigned long flags;
1035
1036 spin_lock_irqsave(&floppy_hlt_lock, flags);
1037 if (!hlt_disabled) {
1038 hlt_disabled = 1;
1039#ifdef HAVE_DISABLE_HLT
1040 disable_hlt();
1041#endif
1042 }
1043 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1044}
1045
1046static void floppy_enable_hlt(void)
1047{
1048 unsigned long flags;
1049
1050 spin_lock_irqsave(&floppy_hlt_lock, flags);
1051 if (hlt_disabled) {
1052 hlt_disabled = 0;
1053#ifdef HAVE_DISABLE_HLT
1054 enable_hlt();
1055#endif
1056 }
1057 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1058}
1059
1060static void setup_DMA(void)
1061{
1062 unsigned long f;
1063
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 if (raw_cmd->length == 0) {
1065 int i;
1066
Joe Perchesb46df352010-03-10 15:20:46 -08001067 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001069 pr_cont("%x,", raw_cmd->cmd[i]);
1070 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 cont->done(0);
1072 FDCS->reset = 1;
1073 return;
1074 }
1075 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001076 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 cont->done(0);
1078 FDCS->reset = 1;
1079 return;
1080 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 f = claim_dma_lock();
1082 fd_disable_dma();
1083#ifdef fd_dma_setup
1084 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1085 (raw_cmd->flags & FD_RAW_READ) ?
1086 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1087 release_dma_lock(f);
1088 cont->done(0);
1089 FDCS->reset = 1;
1090 return;
1091 }
1092 release_dma_lock(f);
1093#else
1094 fd_clear_dma_ff();
1095 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1096 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1097 DMA_MODE_READ : DMA_MODE_WRITE);
1098 fd_set_dma_addr(raw_cmd->kernel_data);
1099 fd_set_dma_count(raw_cmd->length);
1100 virtual_dma_port = FDCS->address;
1101 fd_enable_dma();
1102 release_dma_lock(f);
1103#endif
1104 floppy_disable_hlt();
1105}
1106
1107static void show_floppy(void);
1108
1109/* waits until the fdc becomes ready */
1110static int wait_til_ready(void)
1111{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001112 int status;
1113 int counter;
1114
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 if (FDCS->reset)
1116 return -1;
1117 for (counter = 0; counter < 10000; counter++) {
1118 status = fd_inb(FD_STATUS);
1119 if (status & STATUS_READY)
1120 return status;
1121 }
Joe Perches29f1c782010-03-10 15:21:00 -08001122 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1124 show_floppy();
1125 }
1126 FDCS->reset = 1;
1127 return -1;
1128}
1129
1130/* sends a command byte to the fdc */
1131static int output_byte(char byte)
1132{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001133 int status = wait_til_ready();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001135 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001137
1138 if (is_ready_state(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 fd_outb(byte, FD_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 output_log[output_log_pos].data = byte;
1141 output_log[output_log_pos].status = status;
1142 output_log[output_log_pos].jiffies = jiffies;
1143 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 return 0;
1145 }
1146 FDCS->reset = 1;
Joe Perches29f1c782010-03-10 15:21:00 -08001147 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1149 byte, fdc, status);
1150 show_floppy();
1151 }
1152 return -1;
1153}
1154
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155/* gets the response from the fdc */
1156static int result(void)
1157{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001158 int i;
1159 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160
1161 for (i = 0; i < MAX_REPLIES; i++) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001162 status = wait_til_ready();
1163 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 break;
1165 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1166 if ((status & ~STATUS_BUSY) == STATUS_READY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 resultjiffies = jiffies;
1168 resultsize = i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 return i;
1170 }
1171 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1172 reply_buffer[i] = fd_inb(FD_DATA);
1173 else
1174 break;
1175 }
Joe Perches29f1c782010-03-10 15:21:00 -08001176 if (initialized) {
1177 DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1178 fdc, status, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 show_floppy();
1180 }
1181 FDCS->reset = 1;
1182 return -1;
1183}
1184
1185#define MORE_OUTPUT -2
1186/* does the fdc need more output? */
1187static int need_more_output(void)
1188{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001189 int status = wait_til_ready();
Jesper Juhl06f748c2007-10-16 23:30:57 -07001190
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001191 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001193
1194 if (is_ready_state(status))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 return MORE_OUTPUT;
Joe Perches57584c52010-03-10 15:21:00 -08001196
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 return result();
1198}
1199
1200/* Set perpendicular mode as required, based on data rate, if supported.
1201 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1202 */
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02001203static void perpendicular_mode(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204{
1205 unsigned char perp_mode;
1206
1207 if (raw_cmd->rate & 0x40) {
1208 switch (raw_cmd->rate & 3) {
1209 case 0:
1210 perp_mode = 2;
1211 break;
1212 case 3:
1213 perp_mode = 3;
1214 break;
1215 default:
1216 DPRINT("Invalid data rate for perpendicular mode!\n");
1217 cont->done(0);
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001218 FDCS->reset = 1;
1219 /*
1220 * convenient way to return to
1221 * redo without too much hassle
1222 * (deep stack et al.)
1223 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 return;
1225 }
1226 } else
1227 perp_mode = 0;
1228
1229 if (FDCS->perp_mode == perp_mode)
1230 return;
1231 if (FDCS->version >= FDC_82077_ORIG) {
1232 output_byte(FD_PERPENDICULAR);
1233 output_byte(perp_mode);
1234 FDCS->perp_mode = perp_mode;
1235 } else if (perp_mode) {
1236 DPRINT("perpendicular mode not supported by this FDC.\n");
1237 }
1238} /* perpendicular_mode */
1239
1240static int fifo_depth = 0xa;
1241static int no_fifo;
1242
1243static int fdc_configure(void)
1244{
1245 /* Turn on FIFO */
1246 output_byte(FD_CONFIGURE);
1247 if (need_more_output() != MORE_OUTPUT)
1248 return 0;
1249 output_byte(0);
1250 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1251 output_byte(0); /* pre-compensation from track
1252 0 upwards */
1253 return 1;
1254}
1255
1256#define NOMINAL_DTR 500
1257
1258/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1259 * head load time, and DMA disable flag to values needed by floppy.
1260 *
1261 * The value "dtr" is the data transfer rate in Kbps. It is needed
1262 * to account for the data rate-based scaling done by the 82072 and 82077
1263 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1264 * 8272a).
1265 *
1266 * Note that changing the data transfer rate has a (probably deleterious)
1267 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1268 * fdc_specify is called again after each data transfer rate
1269 * change.
1270 *
1271 * srt: 1000 to 16000 in microseconds
1272 * hut: 16 to 240 milliseconds
1273 * hlt: 2 to 254 milliseconds
1274 *
1275 * These values are rounded up to the next highest available delay time.
1276 */
1277static void fdc_specify(void)
1278{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001279 unsigned char spec1;
1280 unsigned char spec2;
1281 unsigned long srt;
1282 unsigned long hlt;
1283 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 unsigned long dtr = NOMINAL_DTR;
1285 unsigned long scale_dtr = NOMINAL_DTR;
1286 int hlt_max_code = 0x7f;
1287 int hut_max_code = 0xf;
1288
1289 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1290 fdc_configure();
1291 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 }
1293
1294 switch (raw_cmd->rate & 0x03) {
1295 case 3:
1296 dtr = 1000;
1297 break;
1298 case 1:
1299 dtr = 300;
1300 if (FDCS->version >= FDC_82078) {
1301 /* chose the default rate table, not the one
1302 * where 1 = 2 Mbps */
1303 output_byte(FD_DRIVESPEC);
1304 if (need_more_output() == MORE_OUTPUT) {
1305 output_byte(UNIT(current_drive));
1306 output_byte(0xc0);
1307 }
1308 }
1309 break;
1310 case 2:
1311 dtr = 250;
1312 break;
1313 }
1314
1315 if (FDCS->version >= FDC_82072) {
1316 scale_dtr = dtr;
1317 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1318 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1319 }
1320
1321 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001322 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee5442010-03-10 15:20:46 -08001323 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 srt = srt / 4;
Joe Perchesa81ee5442010-03-10 15:20:46 -08001325
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 SUPBOUND(srt, 0xf);
1327 INFBOUND(srt, 0);
1328
Julia Lawall061837b2008-09-22 14:57:16 -07001329 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 if (hlt < 0x01)
1331 hlt = 0x01;
1332 else if (hlt > 0x7f)
1333 hlt = hlt_max_code;
1334
Julia Lawall061837b2008-09-22 14:57:16 -07001335 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 if (hut < 0x1)
1337 hut = 0x1;
1338 else if (hut > 0xf)
1339 hut = hut_max_code;
1340
1341 spec1 = (srt << 4) | hut;
1342 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1343
1344 /* If these parameters did not change, just return with success */
1345 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1346 /* Go ahead and set spec1 and spec2 */
1347 output_byte(FD_SPECIFY);
1348 output_byte(FDCS->spec1 = spec1);
1349 output_byte(FDCS->spec2 = spec2);
1350 }
1351} /* fdc_specify */
1352
1353/* Set the FDC's data transfer rate on behalf of the specified drive.
1354 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1355 * of the specify command (i.e. using the fdc_specify function).
1356 */
1357static int fdc_dtr(void)
1358{
1359 /* If data rate not already set to desired value, set it. */
1360 if ((raw_cmd->rate & 3) == FDCS->dtr)
1361 return 0;
1362
1363 /* Set dtr */
1364 fd_outb(raw_cmd->rate & 3, FD_DCR);
1365
1366 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1367 * need a stabilization period of several milliseconds to be
1368 * enforced after data rate changes before R/W operations.
1369 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1370 */
1371 FDCS->dtr = raw_cmd->rate & 3;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001372 return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
1373 (timeout_fn)floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374} /* fdc_dtr */
1375
1376static void tell_sector(void)
1377{
Joe Perchesb46df352010-03-10 15:20:46 -08001378 pr_cont(": track %d, head %d, sector %d, size %d",
1379 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380} /* tell_sector */
1381
Joe Perchesb46df352010-03-10 15:20:46 -08001382static void print_errors(void)
1383{
1384 DPRINT("");
1385 if (ST0 & ST0_ECE) {
1386 pr_cont("Recalibrate failed!");
1387 } else if (ST2 & ST2_CRC) {
1388 pr_cont("data CRC error");
1389 tell_sector();
1390 } else if (ST1 & ST1_CRC) {
1391 pr_cont("CRC error");
1392 tell_sector();
1393 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1394 (ST2 & ST2_MAM)) {
1395 if (!probing) {
1396 pr_cont("sector not found");
1397 tell_sector();
1398 } else
1399 pr_cont("probe failed...");
1400 } else if (ST2 & ST2_WC) { /* seek error */
1401 pr_cont("wrong cylinder");
1402 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1403 pr_cont("bad cylinder");
1404 } else {
1405 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1406 ST0, ST1, ST2);
1407 tell_sector();
1408 }
1409 pr_cont("\n");
1410}
1411
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412/*
1413 * OK, this error interpreting routine is called after a
1414 * DMA read/write has succeeded
1415 * or failed, so we check the results, and copy any buffers.
1416 * hhb: Added better error reporting.
1417 * ak: Made this into a separate routine.
1418 */
1419static int interpret_errors(void)
1420{
1421 char bad;
1422
1423 if (inr != 7) {
Joe Perches891eda82010-03-10 15:21:05 -08001424 DPRINT("-- FDC reply error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 FDCS->reset = 1;
1426 return 1;
1427 }
1428
1429 /* check IC to find cause of interrupt */
1430 switch (ST0 & ST0_INTR) {
1431 case 0x40: /* error occurred during command execution */
1432 if (ST1 & ST1_EOC)
1433 return 0; /* occurs with pseudo-DMA */
1434 bad = 1;
1435 if (ST1 & ST1_WP) {
1436 DPRINT("Drive is write protected\n");
Joe Perchese0298532010-03-10 15:20:55 -08001437 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 cont->done(0);
1439 bad = 2;
1440 } else if (ST1 & ST1_ND) {
Joe Perchese0298532010-03-10 15:20:55 -08001441 set_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 } else if (ST1 & ST1_OR) {
1443 if (DP->flags & FTD_MSG)
1444 DPRINT("Over/Underrun - retrying\n");
1445 bad = 0;
1446 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001447 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 }
1449 if (ST2 & ST2_WC || ST2 & ST2_BC)
1450 /* wrong cylinder => recal */
1451 DRS->track = NEED_2_RECAL;
1452 return bad;
1453 case 0x80: /* invalid command given */
1454 DPRINT("Invalid FDC command given!\n");
1455 cont->done(0);
1456 return 2;
1457 case 0xc0:
1458 DPRINT("Abnormal termination caused by polling\n");
1459 cont->error();
1460 return 2;
1461 default: /* (0) Normal command termination */
1462 return 0;
1463 }
1464}
1465
1466/*
1467 * This routine is called when everything should be correctly set up
1468 * for the transfer (i.e. floppy motor is on, the correct floppy is
1469 * selected, and the head is sitting on the right track).
1470 */
1471static void setup_rw_floppy(void)
1472{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001473 int i;
1474 int r;
1475 int flags;
1476 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 unsigned long ready_date;
1478 timeout_fn function;
1479
1480 flags = raw_cmd->flags;
1481 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1482 flags |= FD_RAW_INTR;
1483
1484 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1485 ready_date = DRS->spinup_date + DP->spinup;
1486 /* If spinup will take a long time, rerun scandrives
1487 * again just before spinup completion. Beware that
1488 * after scandrives, we must again wait for selection.
1489 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001490 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 ready_date -= DP->select_delay;
Joe Perchesa0a52d62010-03-10 15:20:52 -08001492 function = (timeout_fn)floppy_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 } else
Joe Perchesa0a52d62010-03-10 15:20:52 -08001494 function = (timeout_fn)setup_rw_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495
1496 /* wait until the floppy is spinning fast enough */
1497 if (fd_wait_for_completion(ready_date, function))
1498 return;
1499 }
1500 dflags = DRS->flags;
1501
1502 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1503 setup_DMA();
1504
1505 if (flags & FD_RAW_INTR)
1506 do_floppy = main_command_interrupt;
1507
1508 r = 0;
1509 for (i = 0; i < raw_cmd->cmd_count; i++)
1510 r |= output_byte(raw_cmd->cmd[i]);
1511
Joe Perchesded28632010-03-10 15:21:09 -08001512 debugt(__func__, "rw_command");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513
1514 if (r) {
1515 cont->error();
1516 reset_fdc();
1517 return;
1518 }
1519
1520 if (!(flags & FD_RAW_INTR)) {
1521 inr = result();
1522 cont->interrupt();
1523 } else if (flags & FD_RAW_NEED_DISK)
1524 fd_watchdog();
1525}
1526
1527static int blind_seek;
1528
1529/*
1530 * This is the routine called after every seek (or recalibrate) interrupt
1531 * from the floppy controller.
1532 */
1533static void seek_interrupt(void)
1534{
Joe Perchesded28632010-03-10 15:21:09 -08001535 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1537 DPRINT("seek failed\n");
1538 DRS->track = NEED_2_RECAL;
1539 cont->error();
1540 cont->redo();
1541 return;
1542 }
1543 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
Joe Perches87f530d2010-03-10 15:20:54 -08001544 debug_dcl(DP->flags,
1545 "clearing NEWCHANGE flag because of effective seek\n");
1546 debug_dcl(DP->flags, "jiffies=%lu\n", jiffies);
Joe Perchese0298532010-03-10 15:20:55 -08001547 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
1548 /* effective seek */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 DRS->select_date = jiffies;
1550 }
1551 DRS->track = ST1;
1552 floppy_ready();
1553}
1554
1555static void check_wp(void)
1556{
Joe Perchese0298532010-03-10 15:20:55 -08001557 if (test_bit(FD_VERIFY_BIT, &DRS->flags)) {
1558 /* check write protection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 output_byte(FD_GETSTATUS);
1560 output_byte(UNIT(current_drive));
1561 if (result() != 1) {
1562 FDCS->reset = 1;
1563 return;
1564 }
Joe Perchese0298532010-03-10 15:20:55 -08001565 clear_bit(FD_VERIFY_BIT, &DRS->flags);
1566 clear_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Joe Perches87f530d2010-03-10 15:20:54 -08001567 debug_dcl(DP->flags,
1568 "checking whether disk is write protected\n");
1569 debug_dcl(DP->flags, "wp=%x\n", ST3 & 0x40);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 if (!(ST3 & 0x40))
Joe Perchese0298532010-03-10 15:20:55 -08001571 set_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 else
Joe Perchese0298532010-03-10 15:20:55 -08001573 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 }
1575}
1576
1577static void seek_floppy(void)
1578{
1579 int track;
1580
1581 blind_seek = 0;
1582
Joe Perchesded28632010-03-10 15:21:09 -08001583 debug_dcl(DP->flags, "calling disk change from %s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584
Joe Perchese0298532010-03-10 15:20:55 -08001585 if (!test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1587 /* the media changed flag should be cleared after the seek.
1588 * If it isn't, this means that there is really no disk in
1589 * the drive.
1590 */
Joe Perchese0298532010-03-10 15:20:55 -08001591 set_bit(FD_DISK_CHANGED_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 cont->done(0);
1593 cont->redo();
1594 return;
1595 }
1596 if (DRS->track <= NEED_1_RECAL) {
1597 recalibrate_floppy();
1598 return;
Joe Perchese0298532010-03-10 15:20:55 -08001599 } else if (test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1601 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1602 /* we seek to clear the media-changed condition. Does anybody
1603 * know a more elegant way, which works on all drives? */
1604 if (raw_cmd->track)
1605 track = raw_cmd->track - 1;
1606 else {
1607 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1608 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1609 blind_seek = 1;
1610 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1611 }
1612 track = 1;
1613 }
1614 } else {
1615 check_wp();
1616 if (raw_cmd->track != DRS->track &&
1617 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1618 track = raw_cmd->track;
1619 else {
1620 setup_rw_floppy();
1621 return;
1622 }
1623 }
1624
1625 do_floppy = seek_interrupt;
1626 output_byte(FD_SEEK);
1627 output_byte(UNIT(current_drive));
Joe Perches2300f902010-03-10 15:20:49 -08001628 if (output_byte(track) < 0) {
1629 reset_fdc();
1630 return;
1631 }
Joe Perchesded28632010-03-10 15:21:09 -08001632 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633}
1634
1635static void recal_interrupt(void)
1636{
Joe Perchesded28632010-03-10 15:21:09 -08001637 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 if (inr != 2)
1639 FDCS->reset = 1;
1640 else if (ST0 & ST0_ECE) {
1641 switch (DRS->track) {
1642 case NEED_1_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001643 debugt(__func__, "need 1 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 /* after a second recalibrate, we still haven't
1645 * reached track 0. Probably no drive. Raise an
1646 * error, as failing immediately might upset
1647 * computers possessed by the Devil :-) */
1648 cont->error();
1649 cont->redo();
1650 return;
1651 case NEED_2_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001652 debugt(__func__, "need 2 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 /* If we already did a recalibrate,
1654 * and we are not at track 0, this
1655 * means we have moved. (The only way
1656 * not to move at recalibration is to
1657 * be already at track 0.) Clear the
1658 * new change flag */
Joe Perches87f530d2010-03-10 15:20:54 -08001659 debug_dcl(DP->flags,
1660 "clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661
Joe Perchese0298532010-03-10 15:20:55 -08001662 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 DRS->select_date = jiffies;
1664 /* fall through */
1665 default:
Joe Perchesded28632010-03-10 15:21:09 -08001666 debugt(__func__, "default");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 /* Recalibrate moves the head by at
1668 * most 80 steps. If after one
1669 * recalibrate we don't have reached
1670 * track 0, this might mean that we
1671 * started beyond track 80. Try
1672 * again. */
1673 DRS->track = NEED_1_RECAL;
1674 break;
1675 }
1676 } else
1677 DRS->track = ST1;
1678 floppy_ready();
1679}
1680
1681static void print_result(char *message, int inr)
1682{
1683 int i;
1684
1685 DPRINT("%s ", message);
1686 if (inr >= 0)
1687 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001688 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1689 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690}
1691
1692/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001693irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 int do_print;
1696 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001697 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698
1699 lasthandler = handler;
1700 interruptjiffies = jiffies;
1701
1702 f = claim_dma_lock();
1703 fd_disable_dma();
1704 release_dma_lock(f);
1705
1706 floppy_enable_hlt();
1707 do_floppy = NULL;
1708 if (fdc >= N_FDC || FDCS->address == -1) {
1709 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001710 pr_info("DOR0=%x\n", fdc_state[0].dor);
1711 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
Joe Perches1ebddd82010-03-10 15:21:07 -08001712 pr_info("handler=%pf\n", handler);
Joe Perches275176b2010-03-10 15:21:06 -08001713 is_alive(__func__, "bizarre fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 return IRQ_NONE;
1715 }
1716
1717 FDCS->reset = 0;
1718 /* We have to clear the reset flag here, because apparently on boxes
1719 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1720 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1721 * emission of the SENSEI's.
1722 * It is OK to emit floppy commands because we are in an interrupt
1723 * handler here, and thus we have to fear no interference of other
1724 * activity.
1725 */
1726
Joe Perches29f1c782010-03-10 15:21:00 -08001727 do_print = !handler && print_unex && initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728
1729 inr = result();
1730 if (do_print)
1731 print_result("unexpected interrupt", inr);
1732 if (inr == 0) {
1733 int max_sensei = 4;
1734 do {
1735 output_byte(FD_SENSEI);
1736 inr = result();
1737 if (do_print)
1738 print_result("sensei", inr);
1739 max_sensei--;
Joe Perchesc5297302010-03-10 15:20:58 -08001740 } while ((ST0 & 0x83) != UNIT(current_drive) &&
1741 inr == 2 && max_sensei);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 }
1743 if (!handler) {
1744 FDCS->reset = 1;
1745 return IRQ_NONE;
1746 }
1747 schedule_bh(handler);
Joe Perches275176b2010-03-10 15:21:06 -08001748 is_alive(__func__, "normal interrupt end");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749
1750 /* FIXME! Was it really for us? */
1751 return IRQ_HANDLED;
1752}
1753
1754static void recalibrate_floppy(void)
1755{
Joe Perchesded28632010-03-10 15:21:09 -08001756 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 do_floppy = recal_interrupt;
1758 output_byte(FD_RECALIBRATE);
Joe Perches15b26302010-03-10 15:21:01 -08001759 if (output_byte(UNIT(current_drive)) < 0)
Joe Perches2300f902010-03-10 15:20:49 -08001760 reset_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761}
1762
1763/*
1764 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1765 */
1766static void reset_interrupt(void)
1767{
Joe Perchesded28632010-03-10 15:21:09 -08001768 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 result(); /* get the status ready for set_fdc */
1770 if (FDCS->reset) {
Joe Perches1ebddd82010-03-10 15:21:07 -08001771 pr_info("reset set in interrupt, calling %pf\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 cont->error(); /* a reset just after a reset. BAD! */
1773 }
1774 cont->redo();
1775}
1776
1777/*
1778 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1779 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1780 */
1781static void reset_fdc(void)
1782{
1783 unsigned long flags;
1784
1785 do_floppy = reset_interrupt;
1786 FDCS->reset = 0;
1787 reset_fdc_info(0);
1788
1789 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1790 /* Irrelevant for systems with true DMA (i386). */
1791
1792 flags = claim_dma_lock();
1793 fd_disable_dma();
1794 release_dma_lock(flags);
1795
1796 if (FDCS->version >= FDC_82072A)
1797 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1798 else {
1799 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1800 udelay(FD_RESET_DELAY);
1801 fd_outb(FDCS->dor, FD_DOR);
1802 }
1803}
1804
1805static void show_floppy(void)
1806{
1807 int i;
1808
Joe Perchesb46df352010-03-10 15:20:46 -08001809 pr_info("\n");
1810 pr_info("floppy driver state\n");
1811 pr_info("-------------------\n");
Joe Perches1ebddd82010-03-10 15:21:07 -08001812 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%pf\n",
Joe Perchesb46df352010-03-10 15:20:46 -08001813 jiffies, interruptjiffies, jiffies - interruptjiffies,
1814 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815
Joe Perchesb46df352010-03-10 15:20:46 -08001816 pr_info("timeout_message=%s\n", timeout_message);
1817 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001819 pr_info("%2x %2x %lu\n",
1820 output_log[(i + output_log_pos) % OLOGSIZE].data,
1821 output_log[(i + output_log_pos) % OLOGSIZE].status,
1822 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1823 pr_info("last result at %lu\n", resultjiffies);
1824 pr_info("last redo_fd_request at %lu\n", lastredo);
1825 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1826 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827
Joe Perchesb46df352010-03-10 15:20:46 -08001828 pr_info("status=%x\n", fd_inb(FD_STATUS));
1829 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 if (do_floppy)
Joe Perches1ebddd82010-03-10 15:21:07 -08001831 pr_info("do_floppy=%pf\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001832 if (work_pending(&floppy_work))
Joe Perches1ebddd82010-03-10 15:21:07 -08001833 pr_info("floppy_work.func=%pf\n", floppy_work.func);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 if (timer_pending(&fd_timer))
Joe Perches1ebddd82010-03-10 15:21:07 -08001835 pr_info("fd_timer.function=%pf\n", fd_timer.function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 if (timer_pending(&fd_timeout)) {
Joe Perches1ebddd82010-03-10 15:21:07 -08001837 pr_info("timer_function=%pf\n", fd_timeout.function);
Joe Perchesb46df352010-03-10 15:20:46 -08001838 pr_info("expires=%lu\n", fd_timeout.expires - jiffies);
1839 pr_info("now=%lu\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 }
Joe Perchesb46df352010-03-10 15:20:46 -08001841 pr_info("cont=%p\n", cont);
1842 pr_info("current_req=%p\n", current_req);
1843 pr_info("command_status=%d\n", command_status);
1844 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845}
1846
1847static void floppy_shutdown(unsigned long data)
1848{
1849 unsigned long flags;
1850
Joe Perches29f1c782010-03-10 15:21:00 -08001851 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 show_floppy();
1853 cancel_activity();
1854
1855 floppy_enable_hlt();
1856
1857 flags = claim_dma_lock();
1858 fd_disable_dma();
1859 release_dma_lock(flags);
1860
1861 /* avoid dma going to a random drive after shutdown */
1862
Joe Perches29f1c782010-03-10 15:21:00 -08001863 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 DPRINT("floppy timeout called\n");
1865 FDCS->reset = 1;
1866 if (cont) {
1867 cont->done(0);
1868 cont->redo(); /* this will recall reset when needed */
1869 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001870 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 process_fd_request();
1872 }
Joe Perches275176b2010-03-10 15:21:06 -08001873 is_alive(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874}
1875
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001877static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001879 int mask;
1880 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
1882 mask = 0xfc;
1883 data = UNIT(current_drive);
1884 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1885 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1886 set_debugt();
1887 /* no read since this drive is running */
1888 DRS->first_read_date = 0;
1889 /* note motor start time if motor is not yet running */
1890 DRS->spinup_date = jiffies;
1891 data |= (0x10 << UNIT(current_drive));
1892 }
1893 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1894 mask &= ~(0x10 << UNIT(current_drive));
1895
1896 /* starts motor and selects floppy */
1897 del_timer(motor_off_timer + current_drive);
1898 set_dor(fdc, mask, data);
1899
1900 /* wait_for_completion also schedules reset if needed. */
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001901 return fd_wait_for_completion(DRS->select_date + DP->select_delay,
1902 (timeout_fn)function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903}
1904
1905static void floppy_ready(void)
1906{
Joe Perches045f9832010-03-10 15:20:47 -08001907 if (FDCS->reset) {
1908 reset_fdc();
1909 return;
1910 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 if (start_motor(floppy_ready))
1912 return;
1913 if (fdc_dtr())
1914 return;
1915
Joe Perches87f530d2010-03-10 15:20:54 -08001916 debug_dcl(DP->flags, "calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1918 disk_change(current_drive) && !DP->select_delay)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001919 twaddle(); /* this clears the dcl on certain
1920 * drive/controller combinations */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921
1922#ifdef fd_chose_dma_mode
1923 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1924 unsigned long flags = claim_dma_lock();
1925 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1926 release_dma_lock(flags);
1927 }
1928#endif
1929
1930 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1931 perpendicular_mode();
1932 fdc_specify(); /* must be done here because of hut, hlt ... */
1933 seek_floppy();
1934 } else {
1935 if ((raw_cmd->flags & FD_RAW_READ) ||
1936 (raw_cmd->flags & FD_RAW_WRITE))
1937 fdc_specify();
1938 setup_rw_floppy();
1939 }
1940}
1941
1942static void floppy_start(void)
1943{
Joe Perches73507e62010-03-10 15:21:03 -08001944 reschedule_timeout(current_reqD, "floppy start");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945
1946 scandrives();
Joe Perches87f530d2010-03-10 15:20:54 -08001947 debug_dcl(DP->flags, "setting NEWCHANGE in floppy_start\n");
Joe Perchese0298532010-03-10 15:20:55 -08001948 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 floppy_ready();
1950}
1951
1952/*
1953 * ========================================================================
1954 * here ends the bottom half. Exported routines are:
1955 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
1956 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
1957 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
1958 * and set_dor.
1959 * ========================================================================
1960 */
1961/*
1962 * General purpose continuations.
1963 * ==============================
1964 */
1965
1966static void do_wakeup(void)
1967{
Joe Perches73507e62010-03-10 15:21:03 -08001968 reschedule_timeout(MAXTIMEOUT, "do wakeup");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 cont = NULL;
1970 command_status += 2;
1971 wake_up(&command_done);
1972}
1973
Stephen Hemminger3b06c212010-07-20 20:09:00 -06001974static const struct cont_t wakeup_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 .interrupt = empty,
1976 .redo = do_wakeup,
1977 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07001978 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979};
1980
Stephen Hemminger3b06c212010-07-20 20:09:00 -06001981static const struct cont_t intr_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 .interrupt = empty,
1983 .redo = process_fd_request,
1984 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07001985 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986};
1987
Joe Perches74f63f42010-03-10 15:20:58 -08001988static int wait_til_done(void (*handler)(void), bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989{
1990 int ret;
1991
1992 schedule_bh(handler);
1993
Stephen Hemmingerb862f262010-06-15 13:21:11 +02001994 if (interruptible)
1995 wait_event_interruptible(command_done, command_status >= 2);
1996 else
1997 wait_event(command_done, command_status >= 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998
1999 if (command_status < 2) {
2000 cancel_activity();
2001 cont = &intr_cont;
2002 reset_fdc();
2003 return -EINTR;
2004 }
2005
2006 if (FDCS->reset)
2007 command_status = FD_COMMAND_ERROR;
2008 if (command_status == FD_COMMAND_OKAY)
2009 ret = 0;
2010 else
2011 ret = -EIO;
2012 command_status = FD_COMMAND_NONE;
2013 return ret;
2014}
2015
2016static void generic_done(int result)
2017{
2018 command_status = result;
2019 cont = &wakeup_cont;
2020}
2021
2022static void generic_success(void)
2023{
2024 cont->done(1);
2025}
2026
2027static void generic_failure(void)
2028{
2029 cont->done(0);
2030}
2031
2032static void success_and_wakeup(void)
2033{
2034 generic_success();
2035 cont->redo();
2036}
2037
2038/*
2039 * formatting and rw support.
2040 * ==========================
2041 */
2042
2043static int next_valid_format(void)
2044{
2045 int probed_format;
2046
2047 probed_format = DRS->probed_format;
2048 while (1) {
2049 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2050 DRS->probed_format = 0;
2051 return 1;
2052 }
2053 if (floppy_type[DP->autodetect[probed_format]].sect) {
2054 DRS->probed_format = probed_format;
2055 return 0;
2056 }
2057 probed_format++;
2058 }
2059}
2060
2061static void bad_flp_intr(void)
2062{
2063 int err_count;
2064
2065 if (probing) {
2066 DRS->probed_format++;
2067 if (!next_valid_format())
2068 return;
2069 }
2070 err_count = ++(*errors);
2071 INFBOUND(DRWE->badness, err_count);
2072 if (err_count > DP->max_errors.abort)
2073 cont->done(0);
2074 if (err_count > DP->max_errors.reset)
2075 FDCS->reset = 1;
2076 else if (err_count > DP->max_errors.recal)
2077 DRS->track = NEED_2_RECAL;
2078}
2079
2080static void set_floppy(int drive)
2081{
2082 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002083
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 if (type)
2085 _floppy = floppy_type + type;
2086 else
2087 _floppy = current_type[drive];
2088}
2089
2090/*
2091 * formatting support.
2092 * ===================
2093 */
2094static void format_interrupt(void)
2095{
2096 switch (interpret_errors()) {
2097 case 1:
2098 cont->error();
2099 case 2:
2100 break;
2101 case 0:
2102 cont->done(1);
2103 }
2104 cont->redo();
2105}
2106
Joe Perches48c8cee2010-03-10 15:20:45 -08002107#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002109
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110static void setup_format_params(int track)
2111{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002112 int n;
2113 int il;
2114 int count;
2115 int head_shift;
2116 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 struct fparm {
2118 unsigned char track, head, sect, size;
2119 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120
2121 raw_cmd = &default_raw_cmd;
2122 raw_cmd->track = track;
2123
Joe Perches48c8cee2010-03-10 15:20:45 -08002124 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2125 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 raw_cmd->rate = _floppy->rate & 0x43;
2127 raw_cmd->cmd_count = NR_F;
2128 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2129 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2130 F_SIZECODE = FD_SIZECODE(_floppy);
2131 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2132 F_GAP = _floppy->fmt_gap;
2133 F_FILL = FD_FILL_BYTE;
2134
2135 raw_cmd->kernel_data = floppy_track_buffer;
2136 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2137
2138 /* allow for about 30ms for data transport per track */
2139 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2140
2141 /* a ``cylinder'' is two tracks plus a little stepping time */
2142 track_shift = 2 * head_shift + 3;
2143
2144 /* position of logical sector 1 on this track */
2145 n = (track_shift * format_req.track + head_shift * format_req.head)
2146 % F_SECT_PER_TRACK;
2147
2148 /* determine interleave */
2149 il = 1;
2150 if (_floppy->fmt_gap < 0x22)
2151 il++;
2152
2153 /* initialize field */
2154 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2155 here[count].track = format_req.track;
2156 here[count].head = format_req.head;
2157 here[count].sect = 0;
2158 here[count].size = F_SIZECODE;
2159 }
2160 /* place logical sectors */
2161 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2162 here[n].sect = count;
2163 n = (n + il) % F_SECT_PER_TRACK;
2164 if (here[n].sect) { /* sector busy, find next free sector */
2165 ++n;
2166 if (n >= F_SECT_PER_TRACK) {
2167 n -= F_SECT_PER_TRACK;
2168 while (here[n].sect)
2169 ++n;
2170 }
2171 }
2172 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002173 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002175 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 }
2177}
2178
2179static void redo_format(void)
2180{
2181 buffer_track = -1;
2182 setup_format_params(format_req.track << STRETCH(_floppy));
2183 floppy_start();
Joe Perchesded28632010-03-10 15:21:09 -08002184 debugt(__func__, "queue format request");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185}
2186
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002187static const struct cont_t format_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 .interrupt = format_interrupt,
2189 .redo = redo_format,
2190 .error = bad_flp_intr,
2191 .done = generic_done
2192};
2193
2194static int do_format(int drive, struct format_descr *tmp_format_req)
2195{
2196 int ret;
2197
Joe Perches74f63f42010-03-10 15:20:58 -08002198 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08002199 return -EINTR;
2200
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 set_floppy(drive);
2202 if (!_floppy ||
2203 _floppy->track > DP->tracks ||
2204 tmp_format_req->track >= _floppy->track ||
2205 tmp_format_req->head >= _floppy->head ||
2206 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2207 !_floppy->fmt_gap) {
2208 process_fd_request();
2209 return -EINVAL;
2210 }
2211 format_req = *tmp_format_req;
2212 format_errors = 0;
2213 cont = &format_cont;
2214 errors = &format_errors;
Joe Perches74f63f42010-03-10 15:20:58 -08002215 ret = wait_til_done(redo_format, true);
Joe Perches55eee802010-03-10 15:20:57 -08002216 if (ret == -EINTR)
2217 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 process_fd_request();
2219 return ret;
2220}
2221
2222/*
2223 * Buffer read/write and support
2224 * =============================
2225 */
2226
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002227static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228{
2229 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002230 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231
2232 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002233 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002234 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002235 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237
2238 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002239 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 current_req = NULL;
2241}
2242
2243/* new request_done. Can handle physical sectors which are smaller than a
2244 * logical buffer */
2245static void request_done(int uptodate)
2246{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 struct request *req = current_req;
Jens Axboe48821182010-09-22 09:32:36 +02002248 struct request_queue *q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 unsigned long flags;
2250 int block;
Joe Perches73507e62010-03-10 15:21:03 -08002251 char msg[sizeof("request done ") + sizeof(int) * 3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252
2253 probing = 0;
Joe Perches73507e62010-03-10 15:21:03 -08002254 snprintf(msg, sizeof(msg), "request done %d", uptodate);
2255 reschedule_timeout(MAXTIMEOUT, msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256
2257 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002258 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 return;
2260 }
2261
Jens Axboe48821182010-09-22 09:32:36 +02002262 q = req->q;
2263
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 if (uptodate) {
2265 /* maintain values for invalidation on geometry
2266 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002267 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 INFBOUND(DRS->maxblock, block);
2269 if (block > _floppy->sect)
2270 DRS->maxtrack = 1;
2271
2272 /* unlock chained buffers */
2273 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002274 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 spin_unlock_irqrestore(q->queue_lock, flags);
2276 } else {
2277 if (rq_data_dir(req) == WRITE) {
2278 /* record write error information */
2279 DRWE->write_errors++;
2280 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002281 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 DRWE->first_error_generation = DRS->generation;
2283 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002284 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 DRWE->last_error_generation = DRS->generation;
2286 }
2287 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002288 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 spin_unlock_irqrestore(q->queue_lock, flags);
2290 }
2291}
2292
2293/* Interrupt handler evaluating the result of the r/w operation */
2294static void rw_interrupt(void)
2295{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002296 int eoc;
2297 int ssize;
2298 int heads;
2299 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300
2301 if (R_HEAD >= 2) {
2302 /* some Toshiba floppy controllers occasionnally seem to
2303 * return bogus interrupts after read/write operations, which
2304 * can be recognized by a bad head number (>= 2) */
2305 return;
2306 }
2307
2308 if (!DRS->first_read_date)
2309 DRS->first_read_date = jiffies;
2310
2311 nr_sectors = 0;
Joe Perches712e1de2010-03-10 15:21:10 -08002312 ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313
2314 if (ST1 & ST1_EOC)
2315 eoc = 1;
2316 else
2317 eoc = 0;
2318
2319 if (COMMAND & 0x80)
2320 heads = 2;
2321 else
2322 heads = 1;
2323
2324 nr_sectors = (((R_TRACK - TRACK) * heads +
2325 R_HEAD - HEAD) * SECT_PER_TRACK +
2326 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2327
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002329 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 DPRINT("long rw: %x instead of %lx\n",
2331 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002332 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2333 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2334 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2335 pr_info("heads=%d eoc=%d\n", heads, eoc);
2336 pr_info("spt=%d st=%d ss=%d\n",
2337 SECT_PER_TRACK, fsector_t, ssize);
2338 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340
2341 nr_sectors -= in_sector_offset;
2342 INFBOUND(nr_sectors, 0);
2343 SUPBOUND(current_count_sectors, nr_sectors);
2344
2345 switch (interpret_errors()) {
2346 case 2:
2347 cont->redo();
2348 return;
2349 case 1:
2350 if (!current_count_sectors) {
2351 cont->error();
2352 cont->redo();
2353 return;
2354 }
2355 break;
2356 case 0:
2357 if (!current_count_sectors) {
2358 cont->redo();
2359 return;
2360 }
2361 current_type[current_drive] = _floppy;
2362 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2363 break;
2364 }
2365
2366 if (probing) {
2367 if (DP->flags & FTD_MSG)
2368 DPRINT("Auto-detected floppy type %s in fd%d\n",
2369 _floppy->name, current_drive);
2370 current_type[current_drive] = _floppy;
2371 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2372 probing = 0;
2373 }
2374
2375 if (CT(COMMAND) != FD_READ ||
2376 raw_cmd->kernel_data == current_req->buffer) {
2377 /* transfer directly from buffer */
2378 cont->done(1);
2379 } else if (CT(COMMAND) == FD_READ) {
2380 buffer_track = raw_cmd->track;
2381 buffer_drive = current_drive;
2382 INFBOUND(buffer_max, nr_sectors + fsector_t);
2383 }
2384 cont->redo();
2385}
2386
2387/* Compute maximal contiguous buffer size. */
2388static int buffer_chain_size(void)
2389{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 struct bio_vec *bv;
NeilBrown5705f702007-09-25 12:35:59 +02002391 int size;
2392 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393 char *base;
2394
2395 base = bio_data(current_req->bio);
2396 size = 0;
2397
NeilBrown5705f702007-09-25 12:35:59 +02002398 rq_for_each_segment(bv, current_req, iter) {
2399 if (page_address(bv->bv_page) + bv->bv_offset != base + size)
2400 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401
NeilBrown5705f702007-09-25 12:35:59 +02002402 size += bv->bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 }
2404
2405 return size >> 9;
2406}
2407
2408/* Compute the maximal transfer size */
2409static int transfer_size(int ssize, int max_sector, int max_size)
2410{
2411 SUPBOUND(max_sector, fsector_t + max_size);
2412
2413 /* alignment */
2414 max_sector -= (max_sector % _floppy->sect) % ssize;
2415
2416 /* transfer size, beginning not aligned */
2417 current_count_sectors = max_sector - fsector_t;
2418
2419 return max_sector;
2420}
2421
2422/*
2423 * Move data from/to the track buffer to/from the buffer cache.
2424 */
2425static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2426{
2427 int remaining; /* number of transferred 512-byte sectors */
2428 struct bio_vec *bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002429 char *buffer;
2430 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002431 int size;
2432 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433
2434 max_sector = transfer_size(ssize,
2435 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002436 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437
2438 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002439 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002441 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442
2443 remaining = current_count_sectors << 9;
Tejun Heo1011c1b2009-05-07 22:24:45 +09002444 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002446 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2447 pr_info("remaining=%d\n", remaining >> 9);
2448 pr_info("current_req->nr_sectors=%u\n",
2449 blk_rq_sectors(current_req));
2450 pr_info("current_req->current_nr_sectors=%u\n",
2451 blk_rq_cur_sectors(current_req));
2452 pr_info("max_sector=%d\n", max_sector);
2453 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455
2456 buffer_max = max(max_sector, buffer_max);
2457
2458 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2459
Tejun Heo1011c1b2009-05-07 22:24:45 +09002460 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461
NeilBrown5705f702007-09-25 12:35:59 +02002462 rq_for_each_segment(bv, current_req, iter) {
2463 if (!remaining)
2464 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465
NeilBrown5705f702007-09-25 12:35:59 +02002466 size = bv->bv_len;
2467 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468
NeilBrown5705f702007-09-25 12:35:59 +02002469 buffer = page_address(bv->bv_page) + bv->bv_offset;
NeilBrown5705f702007-09-25 12:35:59 +02002470 if (dma_buffer + size >
2471 floppy_track_buffer + (max_buffer_sectors << 10) ||
2472 dma_buffer < floppy_track_buffer) {
2473 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002474 (int)((floppy_track_buffer - dma_buffer) >> 9));
2475 pr_info("fsector_t=%d buffer_min=%d\n",
2476 fsector_t, buffer_min);
2477 pr_info("current_count_sectors=%ld\n",
2478 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002480 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002481 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002482 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002483 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 }
NeilBrown5705f702007-09-25 12:35:59 +02002485 if (((unsigned long)buffer) % 512)
2486 DPRINT("%p buffer not aligned\n", buffer);
Joe Perches1a23d132010-03-10 15:21:04 -08002487
NeilBrown5705f702007-09-25 12:35:59 +02002488 if (CT(COMMAND) == FD_READ)
2489 memcpy(buffer, dma_buffer, size);
2490 else
2491 memcpy(dma_buffer, buffer, size);
2492
2493 remaining -= size;
2494 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 if (remaining) {
2497 if (remaining > 0)
2498 max_sector -= remaining >> 9;
2499 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501}
2502
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503/* work around a bug in pseudo DMA
2504 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2505 * sending data. Hence we need a different way to signal the
2506 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2507 * does not work with MT, hence we can only transfer one head at
2508 * a time
2509 */
2510static void virtualdmabug_workaround(void)
2511{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002512 int hard_sectors;
2513 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514
2515 if (CT(COMMAND) == FD_WRITE) {
2516 COMMAND &= ~0x80; /* switch off multiple track mode */
2517
2518 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2519 end_sector = SECTOR + hard_sectors - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002521 pr_info("too many sectors %d > %d\n",
2522 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 return;
2524 }
Joe Perches48c8cee2010-03-10 15:20:45 -08002525 SECT_PER_TRACK = end_sector;
2526 /* make sure SECT_PER_TRACK
2527 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 }
2529}
2530
2531/*
2532 * Formulate a read/write request.
2533 * this routine decides where to load the data (directly to buffer, or to
2534 * tmp floppy area), how much data to load (the size of the buffer, the whole
2535 * track, or a single sector)
2536 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2537 * allocation on the fly, it should be done here. No other part should need
2538 * modification.
2539 */
2540
2541static int make_raw_rw_request(void)
2542{
2543 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002544 int max_sector;
2545 int max_size;
2546 int tracksize;
2547 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002549 if (WARN(max_buffer_sectors == 0, "VFS: Block I/O scheduled on unopened device\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551
2552 set_fdc((long)current_req->rq_disk->private_data);
2553
2554 raw_cmd = &default_raw_cmd;
2555 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
2556 FD_RAW_NEED_SEEK;
2557 raw_cmd->cmd_count = NR_RW;
2558 if (rq_data_dir(current_req) == READ) {
2559 raw_cmd->flags |= FD_RAW_READ;
2560 COMMAND = FM_MODE(_floppy, FD_READ);
2561 } else if (rq_data_dir(current_req) == WRITE) {
2562 raw_cmd->flags |= FD_RAW_WRITE;
2563 COMMAND = FM_MODE(_floppy, FD_WRITE);
2564 } else {
Joe Perches275176b2010-03-10 15:21:06 -08002565 DPRINT("%s: unknown command\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 return 0;
2567 }
2568
2569 max_sector = _floppy->sect * _floppy->head;
2570
Tejun Heo83096eb2009-05-07 22:24:39 +09002571 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2572 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002574 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 current_count_sectors = 1;
2576 return 1;
2577 } else
2578 return 0;
2579 }
2580 HEAD = fsector_t / _floppy->sect;
2581
Keith Wansbrough9e491842008-09-22 14:57:17 -07002582 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Joe Perchese0298532010-03-10 15:20:55 -08002583 test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags)) &&
2584 fsector_t < _floppy->sect)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 max_sector = _floppy->sect;
2586
2587 /* 2M disks have phantom sectors on the first track */
2588 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2589 max_sector = 2 * _floppy->sect / 3;
2590 if (fsector_t >= max_sector) {
2591 current_count_sectors =
2592 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002593 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 return 1;
2595 }
2596 SIZECODE = 2;
2597 } else
2598 SIZECODE = FD_SIZECODE(_floppy);
2599 raw_cmd->rate = _floppy->rate & 0x43;
2600 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2601 raw_cmd->rate = 1;
2602
2603 if (SIZECODE)
2604 SIZECODE2 = 0xff;
2605 else
2606 SIZECODE2 = 0x80;
2607 raw_cmd->track = TRACK << STRETCH(_floppy);
2608 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2609 GAP = _floppy->gap;
Joe Perches712e1de2010-03-10 15:21:10 -08002610 ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2612 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002613 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614
2615 /* tracksize describes the size which can be filled up with sectors
2616 * of size ssize.
2617 */
2618 tracksize = _floppy->sect - _floppy->sect % ssize;
2619 if (tracksize < _floppy->sect) {
2620 SECT_PER_TRACK++;
2621 if (tracksize <= fsector_t % _floppy->sect)
2622 SECTOR--;
2623
2624 /* if we are beyond tracksize, fill up using smaller sectors */
2625 while (tracksize <= fsector_t % _floppy->sect) {
2626 while (tracksize + ssize > _floppy->sect) {
2627 SIZECODE--;
2628 ssize >>= 1;
2629 }
2630 SECTOR++;
2631 SECT_PER_TRACK++;
2632 tracksize += ssize;
2633 }
2634 max_sector = HEAD * _floppy->sect + tracksize;
2635 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2636 max_sector = _floppy->sect;
2637 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2638 /* for virtual DMA bug workaround */
2639 max_sector = _floppy->sect;
2640 }
2641
2642 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2643 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002644 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 if ((raw_cmd->track == buffer_track) &&
2646 (current_drive == buffer_drive) &&
2647 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2648 /* data already in track buffer */
2649 if (CT(COMMAND) == FD_READ) {
2650 copy_buffer(1, max_sector, buffer_max);
2651 return 1;
2652 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002653 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 if (CT(COMMAND) == FD_WRITE) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002655 unsigned int sectors;
2656
2657 sectors = fsector_t + blk_rq_sectors(current_req);
2658 if (sectors > ssize && sectors < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 max_size = ssize + ssize;
2660 else
2661 max_size = ssize;
2662 }
2663 raw_cmd->flags &= ~FD_RAW_WRITE;
2664 raw_cmd->flags |= FD_RAW_READ;
2665 COMMAND = FM_MODE(_floppy, FD_READ);
2666 } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) {
2667 unsigned long dma_limit;
2668 int direct, indirect;
2669
2670 indirect =
2671 transfer_size(ssize, max_sector,
2672 max_buffer_sectors * 2) - fsector_t;
2673
2674 /*
2675 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2676 * on a 64 bit machine!
2677 */
2678 max_size = buffer_chain_size();
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002679 dma_limit = (MAX_DMA_ADDRESS -
2680 ((unsigned long)current_req->buffer)) >> 9;
Joe Perchesa81ee5442010-03-10 15:20:46 -08002681 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 /* 64 kb boundaries */
2684 if (CROSS_64KB(current_req->buffer, max_size << 9))
2685 max_size = (K_64 -
2686 ((unsigned long)current_req->buffer) %
2687 K_64) >> 9;
2688 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2689 /*
2690 * We try to read tracks, but if we get too many errors, we
2691 * go back to reading just one sector at a time.
2692 *
2693 * This means we should be able to read a sector even if there
2694 * are other bad sectors on this track.
2695 */
2696 if (!direct ||
2697 (indirect * 2 > direct * 3 &&
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002698 *errors < DP->max_errors.read_track &&
2699 ((!probing ||
2700 (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002701 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 } else {
2703 raw_cmd->kernel_data = current_req->buffer;
2704 raw_cmd->length = current_count_sectors << 9;
2705 if (raw_cmd->length == 0) {
Joe Perches275176b2010-03-10 15:21:06 -08002706 DPRINT("%s: zero dma transfer attempted\n", __func__);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002707 DPRINT("indirect=%d direct=%d fsector_t=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 indirect, direct, fsector_t);
2709 return 0;
2710 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 virtualdmabug_workaround();
2712 return 2;
2713 }
2714 }
2715
2716 if (CT(COMMAND) == FD_READ)
2717 max_size = max_sector; /* unbounded */
2718
2719 /* claim buffer track if needed */
2720 if (buffer_track != raw_cmd->track || /* bad track */
2721 buffer_drive != current_drive || /* bad drive */
2722 fsector_t > buffer_max ||
2723 fsector_t < buffer_min ||
2724 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002725 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 max_sector > 2 * max_buffer_sectors + buffer_min &&
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002727 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
2728 /* not enough space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 buffer_track = -1;
2730 buffer_drive = current_drive;
2731 buffer_max = buffer_min = aligned_sector_t;
2732 }
2733 raw_cmd->kernel_data = floppy_track_buffer +
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002734 ((aligned_sector_t - buffer_min) << 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735
2736 if (CT(COMMAND) == FD_WRITE) {
2737 /* copy write buffer to track buffer.
2738 * if we get here, we know that the write
2739 * is either aligned or the data already in the buffer
2740 * (buffer will be overwritten) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 if (in_sector_offset && buffer_track == -1)
2742 DPRINT("internal error offset !=0 on write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 buffer_track = raw_cmd->track;
2744 buffer_drive = current_drive;
2745 copy_buffer(ssize, max_sector,
2746 2 * max_buffer_sectors + buffer_min);
2747 } else
2748 transfer_size(ssize, max_sector,
2749 2 * max_buffer_sectors + buffer_min -
2750 aligned_sector_t);
2751
2752 /* round up current_count_sectors to get dma xfer size */
2753 raw_cmd->length = in_sector_offset + current_count_sectors;
2754 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2755 raw_cmd->length <<= 9;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 if ((raw_cmd->length < current_count_sectors << 9) ||
2757 (raw_cmd->kernel_data != current_req->buffer &&
2758 CT(COMMAND) == FD_WRITE &&
2759 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2760 aligned_sector_t < buffer_min)) ||
2761 raw_cmd->length % (128 << SIZECODE) ||
2762 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2763 DPRINT("fractionary current count b=%lx s=%lx\n",
2764 raw_cmd->length, current_count_sectors);
2765 if (raw_cmd->kernel_data != current_req->buffer)
Joe Perchesb46df352010-03-10 15:20:46 -08002766 pr_info("addr=%d, length=%ld\n",
2767 (int)((raw_cmd->kernel_data -
2768 floppy_track_buffer) >> 9),
2769 current_count_sectors);
2770 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2771 fsector_t, aligned_sector_t, max_sector, max_size);
2772 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2773 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2774 COMMAND, SECTOR, HEAD, TRACK);
2775 pr_info("buffer drive=%d\n", buffer_drive);
2776 pr_info("buffer track=%d\n", buffer_track);
2777 pr_info("buffer_min=%d\n", buffer_min);
2778 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 return 0;
2780 }
2781
2782 if (raw_cmd->kernel_data != current_req->buffer) {
2783 if (raw_cmd->kernel_data < floppy_track_buffer ||
2784 current_count_sectors < 0 ||
2785 raw_cmd->length < 0 ||
2786 raw_cmd->kernel_data + raw_cmd->length >
2787 floppy_track_buffer + (max_buffer_sectors << 10)) {
2788 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002789 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2790 fsector_t, buffer_min, raw_cmd->length >> 9);
2791 pr_info("current_count_sectors=%ld\n",
2792 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002794 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002796 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 return 0;
2798 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002799 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002800 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 DPRINT("buffer overrun in direct transfer\n");
2802 return 0;
2803 } else if (raw_cmd->length < current_count_sectors << 9) {
2804 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002805 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2806 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 }
2808 if (raw_cmd->length == 0) {
2809 DPRINT("zero dma transfer attempted from make_raw_request\n");
2810 return 0;
2811 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812
2813 virtualdmabug_workaround();
2814 return 2;
2815}
2816
Jens Axboe48821182010-09-22 09:32:36 +02002817/*
2818 * Round-robin between our available drives, doing one request from each
2819 */
2820static int set_next_request(void)
2821{
2822 struct request_queue *q;
2823 int old_pos = fdc_queue;
2824
2825 do {
2826 q = disks[fdc_queue]->queue;
2827 if (++fdc_queue == N_DRIVE)
2828 fdc_queue = 0;
2829 if (q) {
2830 current_req = blk_fetch_request(q);
2831 if (current_req)
2832 break;
2833 }
2834 } while (fdc_queue != old_pos);
2835
2836 return current_req != NULL;
2837}
2838
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839static void redo_fd_request(void)
2840{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 int drive;
2842 int tmp;
2843
2844 lastredo = jiffies;
2845 if (current_drive < N_DRIVE)
2846 floppy_off(current_drive);
2847
Joe Perches0da31322010-03-10 15:21:03 -08002848do_request:
2849 if (!current_req) {
Jens Axboe48821182010-09-22 09:32:36 +02002850 int pending;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851
Jens Axboe48821182010-09-22 09:32:36 +02002852 spin_lock_irq(&floppy_lock);
2853 pending = set_next_request();
2854 spin_unlock_irq(&floppy_lock);
2855
2856 if (!pending) {
Joe Perches0da31322010-03-10 15:21:03 -08002857 do_floppy = NULL;
2858 unlock_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 }
Joe Perches0da31322010-03-10 15:21:03 -08002862 drive = (long)current_req->rq_disk->private_data;
2863 set_fdc(drive);
Joe Perches73507e62010-03-10 15:21:03 -08002864 reschedule_timeout(current_reqD, "redo fd request");
Joe Perches0da31322010-03-10 15:21:03 -08002865
2866 set_floppy(drive);
2867 raw_cmd = &default_raw_cmd;
2868 raw_cmd->flags = 0;
2869 if (start_motor(redo_fd_request))
2870 return;
2871
2872 disk_change(current_drive);
2873 if (test_bit(current_drive, &fake_change) ||
2874 test_bit(FD_DISK_CHANGED_BIT, &DRS->flags)) {
2875 DPRINT("disk absent or changed during operation\n");
2876 request_done(0);
2877 goto do_request;
2878 }
2879 if (!_floppy) { /* Autodetection */
2880 if (!probing) {
2881 DRS->probed_format = 0;
2882 if (next_valid_format()) {
2883 DPRINT("no autodetectable formats\n");
2884 _floppy = NULL;
2885 request_done(0);
2886 goto do_request;
2887 }
2888 }
2889 probing = 1;
2890 _floppy = floppy_type + DP->autodetect[DRS->probed_format];
2891 } else
2892 probing = 0;
2893 errors = &(current_req->errors);
2894 tmp = make_raw_rw_request();
2895 if (tmp < 2) {
2896 request_done(tmp);
2897 goto do_request;
2898 }
2899
2900 if (test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags))
2901 twaddle();
2902 schedule_bh(floppy_start);
Joe Perchesded28632010-03-10 15:21:09 -08002903 debugt(__func__, "queue fd request");
Joe Perches0da31322010-03-10 15:21:03 -08002904 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905}
2906
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002907static const struct cont_t rw_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 .interrupt = rw_interrupt,
2909 .redo = redo_fd_request,
2910 .error = bad_flp_intr,
2911 .done = request_done
2912};
2913
2914static void process_fd_request(void)
2915{
2916 cont = &rw_cont;
2917 schedule_bh(redo_fd_request);
2918}
2919
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002920static void do_fd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921{
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002922 if (WARN(max_buffer_sectors == 0,
2923 "VFS: %s called on non-open device\n", __func__))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002926 if (WARN(atomic_read(&usage_count) == 0,
2927 "warning: usage count=0, current_req=%p sect=%ld type=%x flags=%x\n",
2928 current_req, (long)blk_rq_pos(current_req), current_req->cmd_type,
2929 current_req->cmd_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 return;
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002931
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 if (test_bit(0, &fdc_busy)) {
2933 /* fdc busy, this new request will be treated when the
2934 current one is done */
Joe Perches275176b2010-03-10 15:21:06 -08002935 is_alive(__func__, "old request running");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 return;
2937 }
Joe Perches74f63f42010-03-10 15:20:58 -08002938 lock_fdc(MAXTIMEOUT, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 process_fd_request();
Joe Perches275176b2010-03-10 15:21:06 -08002940 is_alive(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941}
2942
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002943static const struct cont_t poll_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 .interrupt = success_and_wakeup,
2945 .redo = floppy_ready,
2946 .error = generic_failure,
2947 .done = generic_done
2948};
2949
Joe Perches74f63f42010-03-10 15:20:58 -08002950static int poll_drive(bool interruptible, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 /* no auto-sense, just clear dcl */
2953 raw_cmd = &default_raw_cmd;
2954 raw_cmd->flags = flag;
2955 raw_cmd->track = 0;
2956 raw_cmd->cmd_count = 0;
2957 cont = &poll_cont;
Joe Perches87f530d2010-03-10 15:20:54 -08002958 debug_dcl(DP->flags, "setting NEWCHANGE in poll_drive\n");
Joe Perchese0298532010-03-10 15:20:55 -08002959 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Joe Perches55eee802010-03-10 15:20:57 -08002960
2961 return wait_til_done(floppy_ready, interruptible);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962}
2963
2964/*
2965 * User triggered reset
2966 * ====================
2967 */
2968
2969static void reset_intr(void)
2970{
Joe Perchesb46df352010-03-10 15:20:46 -08002971 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972}
2973
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002974static const struct cont_t reset_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 .interrupt = reset_intr,
2976 .redo = success_and_wakeup,
2977 .error = generic_failure,
2978 .done = generic_done
2979};
2980
Joe Perches74f63f42010-03-10 15:20:58 -08002981static int user_reset_fdc(int drive, int arg, bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982{
2983 int ret;
2984
Joe Perches52a0d612010-03-10 15:20:53 -08002985 if (lock_fdc(drive, interruptible))
2986 return -EINTR;
2987
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 if (arg == FD_RESET_ALWAYS)
2989 FDCS->reset = 1;
2990 if (FDCS->reset) {
2991 cont = &reset_cont;
Joe Perches55eee802010-03-10 15:20:57 -08002992 ret = wait_til_done(reset_fdc, interruptible);
2993 if (ret == -EINTR)
2994 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 }
2996 process_fd_request();
Joe Perches52a0d612010-03-10 15:20:53 -08002997 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998}
2999
3000/*
3001 * Misc Ioctl's and support
3002 * ========================
3003 */
3004static inline int fd_copyout(void __user *param, const void *address,
3005 unsigned long size)
3006{
3007 return copy_to_user(param, address, size) ? -EFAULT : 0;
3008}
3009
Joe Perches48c8cee2010-03-10 15:20:45 -08003010static inline int fd_copyin(void __user *param, void *address,
3011 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012{
3013 return copy_from_user(address, param, size) ? -EFAULT : 0;
3014}
3015
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003016static const char *drive_name(int type, int drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017{
3018 struct floppy_struct *floppy;
3019
3020 if (type)
3021 floppy = floppy_type + type;
3022 else {
3023 if (UDP->native_format)
3024 floppy = floppy_type + UDP->native_format;
3025 else
3026 return "(null)";
3027 }
3028 if (floppy->name)
3029 return floppy->name;
3030 else
3031 return "(null)";
3032}
3033
3034/* raw commands */
3035static void raw_cmd_done(int flag)
3036{
3037 int i;
3038
3039 if (!flag) {
3040 raw_cmd->flags |= FD_RAW_FAILURE;
3041 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3042 } else {
3043 raw_cmd->reply_count = inr;
3044 if (raw_cmd->reply_count > MAX_REPLIES)
3045 raw_cmd->reply_count = 0;
3046 for (i = 0; i < raw_cmd->reply_count; i++)
3047 raw_cmd->reply[i] = reply_buffer[i];
3048
3049 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3050 unsigned long flags;
3051 flags = claim_dma_lock();
3052 raw_cmd->length = fd_get_dma_residue();
3053 release_dma_lock(flags);
3054 }
3055
3056 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3057 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3058 raw_cmd->flags |= FD_RAW_FAILURE;
3059
3060 if (disk_change(current_drive))
3061 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3062 else
3063 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3064 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3065 motor_off_callback(current_drive);
3066
3067 if (raw_cmd->next &&
3068 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3069 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3070 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3071 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3072 raw_cmd = raw_cmd->next;
3073 return;
3074 }
3075 }
3076 generic_done(flag);
3077}
3078
Stephen Hemminger3b06c212010-07-20 20:09:00 -06003079static const struct cont_t raw_cmd_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 .interrupt = success_and_wakeup,
3081 .redo = floppy_start,
3082 .error = generic_failure,
3083 .done = raw_cmd_done
3084};
3085
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003086static int raw_cmd_copyout(int cmd, void __user *param,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 struct floppy_raw_cmd *ptr)
3088{
3089 int ret;
3090
3091 while (ptr) {
Joe Perchesce2f11f2010-03-10 15:21:08 -08003092 ret = copy_to_user(param, ptr, sizeof(*ptr));
Joe Perches86b12b42010-03-10 15:20:56 -08003093 if (ret)
3094 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 param += sizeof(struct floppy_raw_cmd);
3096 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003097 if (ptr->length >= 0 &&
3098 ptr->length <= ptr->buffer_length) {
3099 long length = ptr->buffer_length - ptr->length;
Joe Perches4575b552010-03-10 15:20:55 -08003100 ret = fd_copyout(ptr->data, ptr->kernel_data,
3101 length);
3102 if (ret)
3103 return ret;
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003104 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 }
3106 ptr = ptr->next;
3107 }
Joe Perches7f252712010-03-10 15:21:08 -08003108
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109 return 0;
3110}
3111
3112static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3113{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003114 struct floppy_raw_cmd *next;
3115 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116
3117 this = *ptr;
3118 *ptr = NULL;
3119 while (this) {
3120 if (this->buffer_length) {
3121 fd_dma_mem_free((unsigned long)this->kernel_data,
3122 this->buffer_length);
3123 this->buffer_length = 0;
3124 }
3125 next = this->next;
3126 kfree(this);
3127 this = next;
3128 }
3129}
3130
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003131static int raw_cmd_copyin(int cmd, void __user *param,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 struct floppy_raw_cmd **rcmd)
3133{
3134 struct floppy_raw_cmd *ptr;
3135 int ret;
3136 int i;
3137
3138 *rcmd = NULL;
Joe Perches7f252712010-03-10 15:21:08 -08003139
3140loop:
3141 ptr = kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3142 if (!ptr)
3143 return -ENOMEM;
3144 *rcmd = ptr;
3145 ret = copy_from_user(ptr, param, sizeof(*ptr));
3146 if (ret)
3147 return -EFAULT;
3148 ptr->next = NULL;
3149 ptr->buffer_length = 0;
3150 param += sizeof(struct floppy_raw_cmd);
3151 if (ptr->cmd_count > 33)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152 /* the command may now also take up the space
3153 * initially intended for the reply & the
3154 * reply count. Needed for long 82078 commands
3155 * such as RESTORE, which takes ... 17 command
3156 * bytes. Murphy's law #137: When you reserve
3157 * 16 bytes for a structure, you'll one day
3158 * discover that you really need 17...
3159 */
Joe Perches7f252712010-03-10 15:21:08 -08003160 return -EINVAL;
3161
3162 for (i = 0; i < 16; i++)
3163 ptr->reply[i] = 0;
3164 ptr->resultcode = 0;
3165 ptr->kernel_data = NULL;
3166
3167 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3168 if (ptr->length <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 return -EINVAL;
Joe Perches7f252712010-03-10 15:21:08 -08003170 ptr->kernel_data = (char *)fd_dma_mem_alloc(ptr->length);
3171 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3172 if (!ptr->kernel_data)
3173 return -ENOMEM;
3174 ptr->buffer_length = ptr->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175 }
Joe Perches7f252712010-03-10 15:21:08 -08003176 if (ptr->flags & FD_RAW_WRITE) {
3177 ret = fd_copyin(ptr->data, ptr->kernel_data, ptr->length);
3178 if (ret)
3179 return ret;
3180 }
3181
3182 if (ptr->flags & FD_RAW_MORE) {
3183 rcmd = &(ptr->next);
3184 ptr->rate &= 0x43;
3185 goto loop;
3186 }
3187
3188 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189}
3190
3191static int raw_cmd_ioctl(int cmd, void __user *param)
3192{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003194 int drive;
3195 int ret2;
3196 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197
3198 if (FDCS->rawcmd <= 1)
3199 FDCS->rawcmd = 1;
3200 for (drive = 0; drive < N_DRIVE; drive++) {
3201 if (FDC(drive) != fdc)
3202 continue;
3203 if (drive == current_drive) {
3204 if (UDRS->fd_ref > 1) {
3205 FDCS->rawcmd = 2;
3206 break;
3207 }
3208 } else if (UDRS->fd_ref) {
3209 FDCS->rawcmd = 2;
3210 break;
3211 }
3212 }
3213
3214 if (FDCS->reset)
3215 return -EIO;
3216
3217 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3218 if (ret) {
3219 raw_cmd_free(&my_raw_cmd);
3220 return ret;
3221 }
3222
3223 raw_cmd = my_raw_cmd;
3224 cont = &raw_cmd_cont;
Joe Perches74f63f42010-03-10 15:20:58 -08003225 ret = wait_til_done(floppy_start, true);
Joe Perches87f530d2010-03-10 15:20:54 -08003226 debug_dcl(DP->flags, "calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227
3228 if (ret != -EINTR && FDCS->reset)
3229 ret = -EIO;
3230
3231 DRS->track = NO_TRACK;
3232
3233 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3234 if (!ret)
3235 ret = ret2;
3236 raw_cmd_free(&my_raw_cmd);
3237 return ret;
3238}
3239
3240static int invalidate_drive(struct block_device *bdev)
3241{
3242 /* invalidate the buffer track to force a reread */
3243 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3244 process_fd_request();
3245 check_disk_change(bdev);
3246 return 0;
3247}
3248
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003249static int set_geometry(unsigned int cmd, struct floppy_struct *g,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 int drive, int type, struct block_device *bdev)
3251{
3252 int cnt;
3253
3254 /* sanity checking for parameters. */
3255 if (g->sect <= 0 ||
3256 g->head <= 0 ||
3257 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3258 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003259 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 return -EINVAL;
3261 if (type) {
3262 if (!capable(CAP_SYS_ADMIN))
3263 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003264 mutex_lock(&open_lock);
Joe Perches74f63f42010-03-10 15:20:58 -08003265 if (lock_fdc(drive, true)) {
Jiri Slaby8516a502009-06-30 11:41:44 -07003266 mutex_unlock(&open_lock);
3267 return -EINTR;
3268 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 floppy_type[type] = *g;
3270 floppy_type[type].name = "user format";
3271 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3272 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3273 floppy_type[type].size + 1;
3274 process_fd_request();
3275 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3276 struct block_device *bdev = opened_bdev[cnt];
3277 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3278 continue;
Christoph Hellwig2ef41632005-05-05 16:15:59 -07003279 __invalidate_device(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003281 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 } else {
3283 int oldStretch;
Joe Perches52a0d612010-03-10 15:20:53 -08003284
Joe Perches74f63f42010-03-10 15:20:58 -08003285 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003286 return -EINTR;
Joe Perches4575b552010-03-10 15:20:55 -08003287 if (cmd != FDDEFPRM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 /* notice a disk change immediately, else
3289 * we lose our settings immediately*/
Joe Perches74f63f42010-03-10 15:20:58 -08003290 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003291 return -EINTR;
3292 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293 oldStretch = g->stretch;
3294 user_params[drive] = *g;
3295 if (buffer_drive == drive)
3296 SUPBOUND(buffer_max, user_params[drive].sect);
3297 current_type[drive] = &user_params[drive];
3298 floppy_sizes[drive] = user_params[drive].size;
3299 if (cmd == FDDEFPRM)
3300 DRS->keep_data = -1;
3301 else
3302 DRS->keep_data = 1;
3303 /* invalidation. Invalidate only when needed, i.e.
3304 * when there are already sectors in the buffer cache
3305 * whose number will change. This is useful, because
3306 * mtools often changes the geometry of the disk after
3307 * looking at the boot block */
3308 if (DRS->maxblock > user_params[drive].sect ||
3309 DRS->maxtrack ||
3310 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003311 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 invalidate_drive(bdev);
3313 else
3314 process_fd_request();
3315 }
3316 return 0;
3317}
3318
3319/* handle obsolete ioctl's */
Stephen Hemminger21af5442010-06-15 13:21:11 +02003320static unsigned int ioctl_table[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 FDCLRPRM,
3322 FDSETPRM,
3323 FDDEFPRM,
3324 FDGETPRM,
3325 FDMSGON,
3326 FDMSGOFF,
3327 FDFMTBEG,
3328 FDFMTTRK,
3329 FDFMTEND,
3330 FDSETEMSGTRESH,
3331 FDFLUSH,
3332 FDSETMAXERRS,
3333 FDGETMAXERRS,
3334 FDGETDRVTYP,
3335 FDSETDRVPRM,
3336 FDGETDRVPRM,
3337 FDGETDRVSTAT,
3338 FDPOLLDRVSTAT,
3339 FDRESET,
3340 FDGETFDCSTAT,
3341 FDWERRORCLR,
3342 FDWERRORGET,
3343 FDRAWCMD,
3344 FDEJECT,
3345 FDTWADDLE
3346};
3347
Stephen Hemminger21af5442010-06-15 13:21:11 +02003348static int normalize_ioctl(unsigned int *cmd, int *size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349{
3350 int i;
3351
3352 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3353 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3354 *size = _IOC_SIZE(*cmd);
3355 *cmd = ioctl_table[i];
3356 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003357 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 return -EFAULT;
3359 }
3360 return 0;
3361 }
3362 }
3363 return -EINVAL;
3364}
3365
3366static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3367{
3368 if (type)
3369 *g = &floppy_type[type];
3370 else {
Joe Perches74f63f42010-03-10 15:20:58 -08003371 if (lock_fdc(drive, false))
Joe Perches52a0d612010-03-10 15:20:53 -08003372 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003373 if (poll_drive(false, 0) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003374 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 process_fd_request();
3376 *g = current_type[drive];
3377 }
3378 if (!*g)
3379 return -ENODEV;
3380 return 0;
3381}
3382
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003383static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3384{
3385 int drive = (long)bdev->bd_disk->private_data;
3386 int type = ITYPE(drive_state[drive].fd_device);
3387 struct floppy_struct *g;
3388 int ret;
3389
3390 ret = get_floppy_geometry(drive, type, &g);
3391 if (ret)
3392 return ret;
3393
3394 geo->heads = g->head;
3395 geo->sectors = g->sect;
3396 geo->cylinders = g->track;
3397 return 0;
3398}
3399
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003400static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 unsigned long param)
3402{
Al Viroa4af9b42008-03-02 09:27:55 -05003403 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003404 int type = ITYPE(UDRS->fd_device);
3405 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406 int ret;
3407 int size;
3408 union inparam {
3409 struct floppy_struct g; /* geometry */
3410 struct format_descr f;
3411 struct floppy_max_errors max_errors;
3412 struct floppy_drive_params dp;
3413 } inparam; /* parameters coming from user space */
Joe Perches724ee622010-03-10 15:21:11 -08003414 const void *outparam; /* parameters passed back to user space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415
3416 /* convert compatibility eject ioctls into floppy eject ioctl.
3417 * We do this in order to provide a means to eject floppy disks before
3418 * installing the new fdutils package */
3419 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee5442010-03-10 15:20:46 -08003420 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421 DPRINT("obsolete eject ioctl\n");
3422 DPRINT("please use floppycontrol --eject\n");
3423 cmd = FDEJECT;
3424 }
3425
Joe Perchesa81ee5442010-03-10 15:20:46 -08003426 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 return -EINVAL;
3428
Joe Perchesa81ee5442010-03-10 15:20:46 -08003429 /* convert the old style command into a new style command */
Joe Perches4575b552010-03-10 15:20:55 -08003430 ret = normalize_ioctl(&cmd, &size);
3431 if (ret)
3432 return ret;
Joe Perchesa81ee5442010-03-10 15:20:46 -08003433
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 /* permission checks */
Joe Perches0aad92c2010-03-10 15:21:10 -08003435 if (((cmd & 0x40) && !(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL))) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3437 return -EPERM;
3438
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003439 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3440 return -EINVAL;
3441
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442 /* copyin */
Joe Perchesb87c9e02010-03-10 15:20:50 -08003443 memset(&inparam, 0, sizeof(inparam));
Joe Perches4575b552010-03-10 15:20:55 -08003444 if (_IOC_DIR(cmd) & _IOC_WRITE) {
3445 ret = fd_copyin((void __user *)param, &inparam, size);
3446 if (ret)
3447 return ret;
3448 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449
Joe Perchesda273652010-03-10 15:20:52 -08003450 switch (cmd) {
3451 case FDEJECT:
3452 if (UDRS->fd_ref != 1)
3453 /* somebody else has this drive open */
3454 return -EBUSY;
Joe Perches74f63f42010-03-10 15:20:58 -08003455 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003456 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457
Joe Perchesda273652010-03-10 15:20:52 -08003458 /* do the actual eject. Fails on
3459 * non-Sparc architectures */
3460 ret = fd_eject(UNIT(drive));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461
Joe Perchese0298532010-03-10 15:20:55 -08003462 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3463 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Joe Perchesda273652010-03-10 15:20:52 -08003464 process_fd_request();
3465 return ret;
3466 case FDCLRPRM:
Joe Perches74f63f42010-03-10 15:20:58 -08003467 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003468 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003469 current_type[drive] = NULL;
3470 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3471 UDRS->keep_data = 0;
3472 return invalidate_drive(bdev);
3473 case FDSETPRM:
3474 case FDDEFPRM:
3475 return set_geometry(cmd, &inparam.g, drive, type, bdev);
3476 case FDGETPRM:
Joe Perches4575b552010-03-10 15:20:55 -08003477 ret = get_floppy_geometry(drive, type,
Joe Perches724ee622010-03-10 15:21:11 -08003478 (struct floppy_struct **)&outparam);
Joe Perches4575b552010-03-10 15:20:55 -08003479 if (ret)
3480 return ret;
Joe Perchesda273652010-03-10 15:20:52 -08003481 break;
3482 case FDMSGON:
3483 UDP->flags |= FTD_MSG;
3484 return 0;
3485 case FDMSGOFF:
3486 UDP->flags &= ~FTD_MSG;
3487 return 0;
3488 case FDFMTBEG:
Joe Perches74f63f42010-03-10 15:20:58 -08003489 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003490 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003491 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003492 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003493 ret = UDRS->flags;
3494 process_fd_request();
3495 if (ret & FD_VERIFY)
3496 return -ENODEV;
3497 if (!(ret & FD_DISK_WRITABLE))
3498 return -EROFS;
3499 return 0;
3500 case FDFMTTRK:
3501 if (UDRS->fd_ref != 1)
3502 return -EBUSY;
3503 return do_format(drive, &inparam.f);
3504 case FDFMTEND:
3505 case FDFLUSH:
Joe Perches74f63f42010-03-10 15:20:58 -08003506 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003507 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003508 return invalidate_drive(bdev);
3509 case FDSETEMSGTRESH:
3510 UDP->max_errors.reporting = (unsigned short)(param & 0x0f);
3511 return 0;
3512 case FDGETMAXERRS:
Joe Perches724ee622010-03-10 15:21:11 -08003513 outparam = &UDP->max_errors;
Joe Perchesda273652010-03-10 15:20:52 -08003514 break;
3515 case FDSETMAXERRS:
3516 UDP->max_errors = inparam.max_errors;
3517 break;
3518 case FDGETDRVTYP:
3519 outparam = drive_name(type, drive);
Joe Perches724ee622010-03-10 15:21:11 -08003520 SUPBOUND(size, strlen((const char *)outparam) + 1);
Joe Perchesda273652010-03-10 15:20:52 -08003521 break;
3522 case FDSETDRVPRM:
3523 *UDP = inparam.dp;
3524 break;
3525 case FDGETDRVPRM:
Joe Perches724ee622010-03-10 15:21:11 -08003526 outparam = UDP;
Joe Perchesda273652010-03-10 15:20:52 -08003527 break;
3528 case FDPOLLDRVSTAT:
Joe Perches74f63f42010-03-10 15:20:58 -08003529 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003530 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003531 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003532 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003533 process_fd_request();
3534 /* fall through */
3535 case FDGETDRVSTAT:
Joe Perches724ee622010-03-10 15:21:11 -08003536 outparam = UDRS;
Joe Perchesda273652010-03-10 15:20:52 -08003537 break;
3538 case FDRESET:
Joe Perches74f63f42010-03-10 15:20:58 -08003539 return user_reset_fdc(drive, (int)param, true);
Joe Perchesda273652010-03-10 15:20:52 -08003540 case FDGETFDCSTAT:
Joe Perches724ee622010-03-10 15:21:11 -08003541 outparam = UFDCS;
Joe Perchesda273652010-03-10 15:20:52 -08003542 break;
3543 case FDWERRORCLR:
3544 memset(UDRWE, 0, sizeof(*UDRWE));
3545 return 0;
3546 case FDWERRORGET:
Joe Perches724ee622010-03-10 15:21:11 -08003547 outparam = UDRWE;
Joe Perchesda273652010-03-10 15:20:52 -08003548 break;
3549 case FDRAWCMD:
3550 if (type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551 return -EINVAL;
Joe Perches74f63f42010-03-10 15:20:58 -08003552 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003553 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003554 set_floppy(drive);
Joe Perches4575b552010-03-10 15:20:55 -08003555 i = raw_cmd_ioctl(cmd, (void __user *)param);
3556 if (i == -EINTR)
3557 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003558 process_fd_request();
3559 return i;
3560 case FDTWADDLE:
Joe Perches74f63f42010-03-10 15:20:58 -08003561 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003562 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003563 twaddle();
3564 process_fd_request();
3565 return 0;
3566 default:
3567 return -EINVAL;
3568 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569
3570 if (_IOC_DIR(cmd) & _IOC_READ)
3571 return fd_copyout((void __user *)param, outparam, size);
Joe Perchesda273652010-03-10 15:20:52 -08003572
3573 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574}
3575
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003576static int fd_ioctl(struct block_device *bdev, fmode_t mode,
3577 unsigned int cmd, unsigned long param)
3578{
3579 int ret;
3580
3581 lock_kernel();
3582 ret = fd_locked_ioctl(bdev, mode, cmd, param);
3583 unlock_kernel();
3584
3585 return ret;
3586}
3587
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588static void __init config_types(void)
3589{
Joe Perchesb46df352010-03-10 15:20:46 -08003590 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 int drive;
3592
3593 /* read drive info out of physical CMOS */
3594 drive = 0;
3595 if (!UDP->cmos)
3596 UDP->cmos = FLOPPY0_TYPE;
3597 drive = 1;
3598 if (!UDP->cmos && FLOPPY1_TYPE)
3599 UDP->cmos = FLOPPY1_TYPE;
3600
Jesper Juhl06f748c2007-10-16 23:30:57 -07003601 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602
3603 for (drive = 0; drive < N_DRIVE; drive++) {
3604 unsigned int type = UDP->cmos;
3605 struct floppy_drive_params *params;
3606 const char *name = NULL;
3607 static char temparea[32];
3608
Tobias Klauser945f3902006-01-08 01:05:11 -08003609 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 params = &default_drive_params[type].params;
3611 if (type) {
3612 name = default_drive_params[type].name;
3613 allowed_drive_mask |= 1 << drive;
3614 } else
3615 allowed_drive_mask &= ~(1 << drive);
3616 } else {
3617 params = &default_drive_params[0].params;
3618 sprintf(temparea, "unknown type %d (usb?)", type);
3619 name = temparea;
3620 }
3621 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003622 const char *prepend;
3623 if (!has_drive) {
3624 prepend = "";
3625 has_drive = true;
3626 pr_info("Floppy drive(s):");
3627 } else {
3628 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629 }
Joe Perchesb46df352010-03-10 15:20:46 -08003630
3631 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632 }
3633 *UDP = *params;
3634 }
Joe Perchesb46df352010-03-10 15:20:46 -08003635
3636 if (has_drive)
3637 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638}
3639
Al Viroa4af9b42008-03-02 09:27:55 -05003640static int floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641{
Al Viroa4af9b42008-03-02 09:27:55 -05003642 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643
Arnd Bergmann6e9624b2010-08-07 18:25:34 +02003644 lock_kernel();
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003645 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 if (UDRS->fd_ref < 0)
3647 UDRS->fd_ref = 0;
3648 else if (!UDRS->fd_ref--) {
3649 DPRINT("floppy_release with fd_ref == 0");
3650 UDRS->fd_ref = 0;
3651 }
3652 if (!UDRS->fd_ref)
3653 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003654 mutex_unlock(&open_lock);
Arnd Bergmann6e9624b2010-08-07 18:25:34 +02003655 unlock_kernel();
Ingo Molnar3e541a4a2006-07-03 00:24:23 -07003656
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 return 0;
3658}
3659
3660/*
3661 * floppy_open check for aliasing (/dev/fd0 can be the same as
3662 * /dev/PS0 etc), and disallows simultaneous access to the same
3663 * drive with different device numbers.
3664 */
Al Viroa4af9b42008-03-02 09:27:55 -05003665static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666{
Al Viroa4af9b42008-03-02 09:27:55 -05003667 int drive = (long)bdev->bd_disk->private_data;
3668 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 int try;
3670 int res = -EBUSY;
3671 char *tmp;
3672
Arnd Bergmann6e9624b2010-08-07 18:25:34 +02003673 lock_kernel();
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003674 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003676 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 goto out2;
3678
3679 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
Joe Perchese0298532010-03-10 15:20:55 -08003680 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3681 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682 }
3683
Al Viroa4af9b42008-03-02 09:27:55 -05003684 if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685 goto out2;
3686
Al Viroa4af9b42008-03-02 09:27:55 -05003687 if (mode & FMODE_EXCL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 UDRS->fd_ref = -1;
3689 else
3690 UDRS->fd_ref++;
3691
Al Viroa4af9b42008-03-02 09:27:55 -05003692 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693
3694 res = -ENXIO;
3695
3696 if (!floppy_track_buffer) {
3697 /* if opening an ED drive, reserve a big buffer,
3698 * else reserve a small one */
3699 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3700 try = 64; /* Only 48 actually useful */
3701 else
3702 try = 32; /* Only 24 actually useful */
3703
3704 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3705 if (!tmp && !floppy_track_buffer) {
3706 try >>= 1; /* buffer only one side */
3707 INFBOUND(try, 16);
3708 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3709 }
Joe Perchesa81ee5442010-03-10 15:20:46 -08003710 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 if (!tmp && !floppy_track_buffer) {
3713 DPRINT("Unable to allocate DMA memory\n");
3714 goto out;
3715 }
3716 if (floppy_track_buffer) {
3717 if (tmp)
3718 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3719 } else {
3720 buffer_min = buffer_max = -1;
3721 floppy_track_buffer = tmp;
3722 max_buffer_sectors = try;
3723 }
3724 }
3725
Al Viroa4af9b42008-03-02 09:27:55 -05003726 new_dev = MINOR(bdev->bd_dev);
3727 UDRS->fd_device = new_dev;
3728 set_capacity(disks[drive], floppy_sizes[new_dev]);
3729 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730 if (buffer_drive == drive)
3731 buffer_track = -1;
3732 }
3733
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 if (UFDCS->rawcmd == 1)
3735 UFDCS->rawcmd = 2;
3736
Al Viroa4af9b42008-03-02 09:27:55 -05003737 if (!(mode & FMODE_NDELAY)) {
3738 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739 UDRS->last_checked = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003740 check_disk_change(bdev);
Joe Perchese0298532010-03-10 15:20:55 -08003741 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742 goto out;
3743 }
3744 res = -EROFS;
Joe Perchese0298532010-03-10 15:20:55 -08003745 if ((mode & FMODE_WRITE) &&
3746 !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747 goto out;
3748 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003749 mutex_unlock(&open_lock);
Arnd Bergmann6e9624b2010-08-07 18:25:34 +02003750 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751 return 0;
3752out:
3753 if (UDRS->fd_ref < 0)
3754 UDRS->fd_ref = 0;
3755 else
3756 UDRS->fd_ref--;
3757 if (!UDRS->fd_ref)
3758 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003760 mutex_unlock(&open_lock);
Arnd Bergmann6e9624b2010-08-07 18:25:34 +02003761 unlock_kernel();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762 return res;
3763}
3764
3765/*
3766 * Check if the disk has been changed or if a change has been faked.
3767 */
3768static int check_floppy_change(struct gendisk *disk)
3769{
3770 int drive = (long)disk->private_data;
3771
Joe Perchese0298532010-03-10 15:20:55 -08003772 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3773 test_bit(FD_VERIFY_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774 return 1;
3775
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003776 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Joe Perches74f63f42010-03-10 15:20:58 -08003777 lock_fdc(drive, false);
3778 poll_drive(false, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780 }
3781
Joe Perchese0298532010-03-10 15:20:55 -08003782 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3783 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784 test_bit(drive, &fake_change) ||
3785 (!ITYPE(UDRS->fd_device) && !current_type[drive]))
3786 return 1;
3787 return 0;
3788}
3789
3790/*
3791 * This implements "read block 0" for floppy_revalidate().
3792 * Needed for format autodetection, checking whether there is
3793 * a disk in the drive, and whether that disk is writable.
3794 */
3795
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003796static void floppy_rb0_complete(struct bio *bio, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798 complete((struct completion *)bio->bi_private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799}
3800
3801static int __floppy_read_block_0(struct block_device *bdev)
3802{
3803 struct bio bio;
3804 struct bio_vec bio_vec;
3805 struct completion complete;
3806 struct page *page;
3807 size_t size;
3808
3809 page = alloc_page(GFP_NOIO);
3810 if (!page) {
3811 process_fd_request();
3812 return -ENOMEM;
3813 }
3814
3815 size = bdev->bd_block_size;
3816 if (!size)
3817 size = 1024;
3818
3819 bio_init(&bio);
3820 bio.bi_io_vec = &bio_vec;
3821 bio_vec.bv_page = page;
3822 bio_vec.bv_len = size;
3823 bio_vec.bv_offset = 0;
3824 bio.bi_vcnt = 1;
3825 bio.bi_idx = 0;
3826 bio.bi_size = size;
3827 bio.bi_bdev = bdev;
3828 bio.bi_sector = 0;
Stephen Hemminger41a55b42010-06-15 13:21:11 +02003829 bio.bi_flags = BIO_QUIET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830 init_completion(&complete);
3831 bio.bi_private = &complete;
3832 bio.bi_end_io = floppy_rb0_complete;
3833
3834 submit_bio(READ, &bio);
3835 generic_unplug_device(bdev_get_queue(bdev));
3836 process_fd_request();
3837 wait_for_completion(&complete);
3838
3839 __free_page(page);
3840
3841 return 0;
3842}
3843
3844/* revalidate the floppy disk, i.e. trigger format autodetection by reading
3845 * the bootblock (block 0). "Autodetection" is also needed to check whether
3846 * there is a disk in the drive at all... Thus we also do it for fixed
3847 * geometry formats */
3848static int floppy_revalidate(struct gendisk *disk)
3849{
3850 int drive = (long)disk->private_data;
3851#define NO_GEOM (!current_type[drive] && !ITYPE(UDRS->fd_device))
3852 int cf;
3853 int res = 0;
3854
Joe Perchese0298532010-03-10 15:20:55 -08003855 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3856 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
3857 test_bit(drive, &fake_change) || NO_GEOM) {
Stephen Hemminger01b6b672010-06-15 13:21:11 +02003858 if (WARN(atomic_read(&usage_count) == 0,
3859 "VFS: revalidate called on non-open device.\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003860 return -EFAULT;
Stephen Hemminger01b6b672010-06-15 13:21:11 +02003861
Joe Perches74f63f42010-03-10 15:20:58 -08003862 lock_fdc(drive, false);
Joe Perchese0298532010-03-10 15:20:55 -08003863 cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3864 test_bit(FD_VERIFY_BIT, &UDRS->flags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865 if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)) {
3866 process_fd_request(); /*already done by another thread */
3867 return 0;
3868 }
3869 UDRS->maxblock = 0;
3870 UDRS->maxtrack = 0;
3871 if (buffer_drive == drive)
3872 buffer_track = -1;
3873 clear_bit(drive, &fake_change);
Joe Perchese0298532010-03-10 15:20:55 -08003874 clear_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875 if (cf)
3876 UDRS->generation++;
3877 if (NO_GEOM) {
3878 /* auto-sensing */
3879 res = __floppy_read_block_0(opened_bdev[drive]);
3880 } else {
3881 if (cf)
Joe Perches74f63f42010-03-10 15:20:58 -08003882 poll_drive(false, FD_RAW_NEED_DISK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883 process_fd_request();
3884 }
3885 }
3886 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
3887 return res;
3888}
3889
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07003890static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07003891 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05003892 .open = floppy_open,
3893 .release = floppy_release,
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003894 .ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003895 .getgeo = fd_getgeo,
3896 .media_changed = check_floppy_change,
3897 .revalidate_disk = floppy_revalidate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003898};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900/*
3901 * Floppy Driver initialization
3902 * =============================
3903 */
3904
3905/* Determine the floppy disk controller type */
3906/* This routine was written by David C. Niemi */
3907static char __init get_fdc_version(void)
3908{
3909 int r;
3910
3911 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
3912 if (FDCS->reset)
3913 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003914 r = result();
3915 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916 return FDC_NONE; /* No FDC present ??? */
3917 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003918 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3920 }
3921 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003922 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3923 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 return FDC_UNKNOWN;
3925 }
3926
3927 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003928 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3930 }
3931
3932 output_byte(FD_PERPENDICULAR);
3933 if (need_more_output() == MORE_OUTPUT) {
3934 output_byte(0);
3935 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003936 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937 return FDC_82072A; /* 82072A as found on Sparcs. */
3938 }
3939
3940 output_byte(FD_UNLOCK);
3941 r = result();
3942 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003943 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003944 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07003945 * LOCK/UNLOCK */
3946 }
3947 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003948 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3949 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950 return FDC_UNKNOWN;
3951 }
3952 output_byte(FD_PARTID);
3953 r = result();
3954 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003955 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3956 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957 return FDC_UNKNOWN;
3958 }
3959 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003960 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 return FDC_82077; /* Revised 82077AA passes all the tests */
3962 }
3963 switch (reply_buffer[0] >> 5) {
3964 case 0x0:
3965 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08003966 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 return FDC_82078;
3968 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08003969 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970 return FDC_82078;
3971 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08003972 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973 return FDC_S82078B;
3974 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08003975 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976 return FDC_87306;
3977 default:
Joe Perchesb46df352010-03-10 15:20:46 -08003978 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
3979 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980 return FDC_82078_UNKN;
3981 }
3982} /* get_fdc_version */
3983
3984/* lilo configuration */
3985
3986static void __init floppy_set_flags(int *ints, int param, int param2)
3987{
3988 int i;
3989
3990 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
3991 if (param)
3992 default_drive_params[i].params.flags |= param2;
3993 else
3994 default_drive_params[i].params.flags &= ~param2;
3995 }
3996 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
3997}
3998
3999static void __init daring(int *ints, int param, int param2)
4000{
4001 int i;
4002
4003 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4004 if (param) {
4005 default_drive_params[i].params.select_delay = 0;
4006 default_drive_params[i].params.flags |=
4007 FD_SILENT_DCL_CLEAR;
4008 } else {
4009 default_drive_params[i].params.select_delay =
4010 2 * HZ / 100;
4011 default_drive_params[i].params.flags &=
4012 ~FD_SILENT_DCL_CLEAR;
4013 }
4014 }
4015 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
4016}
4017
4018static void __init set_cmos(int *ints, int dummy, int dummy2)
4019{
4020 int current_drive = 0;
4021
4022 if (ints[0] != 2) {
4023 DPRINT("wrong number of parameters for CMOS\n");
4024 return;
4025 }
4026 current_drive = ints[1];
4027 if (current_drive < 0 || current_drive >= 8) {
4028 DPRINT("bad drive for set_cmos\n");
4029 return;
4030 }
4031#if N_FDC > 1
4032 if (current_drive >= 4 && !FDC2)
4033 FDC2 = 0x370;
4034#endif
4035 DP->cmos = ints[2];
4036 DPRINT("setting CMOS code to %d\n", ints[2]);
4037}
4038
4039static struct param_table {
4040 const char *name;
4041 void (*fn) (int *ints, int param, int param2);
4042 int *var;
4043 int def_param;
4044 int param2;
4045} config_params[] __initdata = {
4046 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4047 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4048 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4049 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4050 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4051 {"daring", daring, NULL, 1, 0},
4052#if N_FDC > 1
4053 {"two_fdc", NULL, &FDC2, 0x370, 0},
4054 {"one_fdc", NULL, &FDC2, 0, 0},
4055#endif
4056 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4057 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4058 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4059 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4060 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4061 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4062 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4063 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4064 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4065 {"nofifo", NULL, &no_fifo, 0x20, 0},
4066 {"usefifo", NULL, &no_fifo, 0, 0},
4067 {"cmos", set_cmos, NULL, 0, 0},
4068 {"slow", NULL, &slow_floppy, 1, 0},
4069 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4070 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4071 {"L40SX", NULL, &print_unex, 0, 0}
4072
4073 EXTRA_FLOPPY_PARAMS
4074};
4075
4076static int __init floppy_setup(char *str)
4077{
4078 int i;
4079 int param;
4080 int ints[11];
4081
4082 str = get_options(str, ARRAY_SIZE(ints), ints);
4083 if (str) {
4084 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4085 if (strcmp(str, config_params[i].name) == 0) {
4086 if (ints[0])
4087 param = ints[1];
4088 else
4089 param = config_params[i].def_param;
4090 if (config_params[i].fn)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004091 config_params[i].fn(ints, param,
4092 config_params[i].
4093 param2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094 if (config_params[i].var) {
4095 DPRINT("%s=%d\n", str, param);
4096 *config_params[i].var = param;
4097 }
4098 return 1;
4099 }
4100 }
4101 }
4102 if (str) {
4103 DPRINT("unknown floppy option [%s]\n", str);
4104
4105 DPRINT("allowed options are:");
4106 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004107 pr_cont(" %s", config_params[i].name);
4108 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109 } else
4110 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004111 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112 return 0;
4113}
4114
4115static int have_no_fdc = -ENODEV;
4116
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004117static ssize_t floppy_cmos_show(struct device *dev,
4118 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004119{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004120 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004121 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004122
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004123 drive = p->id;
4124 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004125}
Joe Perches48c8cee2010-03-10 15:20:45 -08004126
Stephen Hemmingerbe1c0fb2010-06-15 13:21:11 +02004127static DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004128
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129static void floppy_device_release(struct device *dev)
4130{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131}
4132
Frans Popc90cd332009-07-25 22:24:54 +02004133static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004134{
4135 int fdc;
4136
4137 for (fdc = 0; fdc < N_FDC; fdc++)
4138 if (FDCS->address != -1)
Joe Perches74f63f42010-03-10 15:20:58 -08004139 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004140
4141 return 0;
4142}
4143
Alexey Dobriyan47145212009-12-14 18:00:08 -08004144static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004145 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004146 .restore = floppy_resume,
4147};
4148
4149static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004150 .driver = {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004151 .name = "floppy",
4152 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004153 },
4154};
4155
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004156static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157
4158static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4159{
4160 int drive = (*part & 3) | ((*part & 0x80) >> 5);
4161 if (drive >= N_DRIVE ||
4162 !(allowed_drive_mask & (1 << drive)) ||
4163 fdc_state[FDC(drive)].version == FDC_NONE)
4164 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004165 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166 return NULL;
4167 *part = 0;
4168 return get_disk(disks[drive]);
4169}
4170
4171static int __init floppy_init(void)
4172{
4173 int i, unit, drive;
4174 int err, dr;
4175
Stephen Hemminger285203c2010-06-15 13:21:11 +02004176 set_debugt();
4177 interruptjiffies = resultjiffies = jiffies;
4178
Kumar Gala68e1ee62008-09-22 14:41:31 -07004179#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004180 if (check_legacy_ioport(FDC1))
4181 return -ENODEV;
4182#endif
4183
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184 raw_cmd = NULL;
4185
4186 for (dr = 0; dr < N_DRIVE; dr++) {
4187 disks[dr] = alloc_disk(1);
4188 if (!disks[dr]) {
4189 err = -ENOMEM;
4190 goto out_put_disk;
4191 }
4192
Jens Axboe48821182010-09-22 09:32:36 +02004193 disks[dr]->queue = blk_init_queue(do_fd_request, &floppy_lock);
4194 if (!disks[dr]->queue) {
4195 err = -ENOMEM;
4196 goto out_put_disk;
4197 }
4198
4199 blk_queue_max_hw_sectors(disks[dr]->queue, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004200 disks[dr]->major = FLOPPY_MAJOR;
4201 disks[dr]->first_minor = TOMINOR(dr);
4202 disks[dr]->fops = &floppy_fops;
4203 sprintf(disks[dr]->disk_name, "fd%d", dr);
4204
4205 init_timer(&motor_off_timer[dr]);
4206 motor_off_timer[dr].data = dr;
4207 motor_off_timer[dr].function = motor_off_callback;
4208 }
4209
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210 err = register_blkdev(FLOPPY_MAJOR, "fd");
4211 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004212 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004214 err = platform_driver_register(&floppy_driver);
4215 if (err)
4216 goto out_unreg_blkdev;
4217
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4219 floppy_find, NULL, NULL);
4220
4221 for (i = 0; i < 256; i++)
4222 if (ITYPE(i))
4223 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4224 else
4225 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4226
Joe Perches73507e62010-03-10 15:21:03 -08004227 reschedule_timeout(MAXTIMEOUT, "floppy init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228 config_types();
4229
4230 for (i = 0; i < N_FDC; i++) {
4231 fdc = i;
Joe Perchesb87c9e02010-03-10 15:20:50 -08004232 memset(FDCS, 0, sizeof(*FDCS));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 FDCS->dtr = -1;
4234 FDCS->dor = 0x4;
4235#if defined(__sparc__) || defined(__mc68000__)
Joe Perches96534f12010-03-10 15:20:51 -08004236 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237#ifdef __mc68000__
4238 if (MACH_IS_SUN3X)
4239#endif
4240 FDCS->version = FDC_82072A;
4241#endif
4242 }
4243
4244 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 fdc_state[0].address = FDC1;
4246 if (fdc_state[0].address == -1) {
4247 del_timer(&fd_timeout);
4248 err = -ENODEV;
4249 goto out_unreg_region;
4250 }
4251#if N_FDC > 1
4252 fdc_state[1].address = FDC2;
4253#endif
4254
4255 fdc = 0; /* reset fdc in case of unexpected interrupt */
4256 err = floppy_grab_irq_and_dma();
4257 if (err) {
4258 del_timer(&fd_timeout);
4259 err = -EBUSY;
4260 goto out_unreg_region;
4261 }
4262
4263 /* initialise drive state */
4264 for (drive = 0; drive < N_DRIVE; drive++) {
Joe Perchesb87c9e02010-03-10 15:20:50 -08004265 memset(UDRS, 0, sizeof(*UDRS));
4266 memset(UDRWE, 0, sizeof(*UDRWE));
Joe Perchese0298532010-03-10 15:20:55 -08004267 set_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
4268 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
4269 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 UDRS->fd_device = -1;
4271 floppy_track_buffer = NULL;
4272 max_buffer_sectors = 0;
4273 }
4274 /*
4275 * Small 10 msec delay to let through any interrupt that
4276 * initialization might have triggered, to not
4277 * confuse detection:
4278 */
4279 msleep(10);
4280
4281 for (i = 0; i < N_FDC; i++) {
4282 fdc = i;
4283 FDCS->driver_version = FD_DRIVER_VERSION;
4284 for (unit = 0; unit < 4; unit++)
4285 FDCS->track[unit] = 0;
4286 if (FDCS->address == -1)
4287 continue;
4288 FDCS->rawcmd = 2;
Joe Perches74f63f42010-03-10 15:20:58 -08004289 if (user_reset_fdc(-1, FD_RESET_ALWAYS, false)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004291 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 FDCS->address = -1;
4293 FDCS->version = FDC_NONE;
4294 continue;
4295 }
4296 /* Try to determine the floppy controller type */
4297 FDCS->version = get_fdc_version();
4298 if (FDCS->version == FDC_NONE) {
4299 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004300 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 FDCS->address = -1;
4302 continue;
4303 }
4304 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4305 can_use_virtual_dma = 0;
4306
4307 have_no_fdc = 0;
4308 /* Not all FDCs seem to be able to handle the version command
4309 * properly, so force a reset for the standard FDC clones,
4310 * to avoid interrupt garbage.
4311 */
Joe Perches74f63f42010-03-10 15:20:58 -08004312 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 }
4314 fdc = 0;
4315 del_timer(&fd_timeout);
4316 current_drive = 0;
Joe Perches29f1c782010-03-10 15:21:00 -08004317 initialized = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318 if (have_no_fdc) {
4319 DPRINT("no floppy controllers found\n");
4320 err = have_no_fdc;
4321 goto out_flush_work;
4322 }
4323
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324 for (drive = 0; drive < N_DRIVE; drive++) {
4325 if (!(allowed_drive_mask & (1 << drive)))
4326 continue;
4327 if (fdc_state[FDC(drive)].version == FDC_NONE)
4328 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004329
4330 floppy_device[drive].name = floppy_device_name;
4331 floppy_device[drive].id = drive;
4332 floppy_device[drive].dev.release = floppy_device_release;
4333
4334 err = platform_device_register(&floppy_device[drive]);
4335 if (err)
4336 goto out_flush_work;
4337
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004338 err = device_create_file(&floppy_device[drive].dev,
4339 &dev_attr_cmos);
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004340 if (err)
4341 goto out_unreg_platform_dev;
4342
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 /* to be cleaned up... */
4344 disks[drive]->private_data = (void *)(long)drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004346 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347 add_disk(disks[drive]);
4348 }
4349
4350 return 0;
4351
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004352out_unreg_platform_dev:
4353 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354out_flush_work:
4355 flush_scheduled_work();
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004356 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357 floppy_release_irq_and_dma();
4358out_unreg_region:
4359 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004360 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361out_unreg_blkdev:
4362 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363out_put_disk:
4364 while (dr--) {
4365 del_timer(&motor_off_timer[dr]);
4366 put_disk(disks[dr]);
Jens Axboe48821182010-09-22 09:32:36 +02004367 if (disks[dr]->queue)
4368 blk_cleanup_queue(disks[dr]->queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 }
4370 return err;
4371}
4372
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004373static const struct io_region {
4374 int offset;
4375 int size;
4376} io_regions[] = {
4377 { 2, 1 },
4378 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4379 { 4, 2 },
4380 /* address + 6 is reserved, and may be taken by IDE.
4381 * Unfortunately, Adaptec doesn't know this :-(, */
4382 { 7, 1 },
4383};
4384
4385static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4386{
4387 while (p != io_regions) {
4388 p--;
4389 release_region(FDCS->address + p->offset, p->size);
4390 }
4391}
4392
4393#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4394
4395static int floppy_request_regions(int fdc)
4396{
4397 const struct io_region *p;
4398
4399 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004400 if (!request_region(FDCS->address + p->offset,
4401 p->size, "floppy")) {
4402 DPRINT("Floppy io-port 0x%04lx in use\n",
4403 FDCS->address + p->offset);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004404 floppy_release_allocated_regions(fdc, p);
4405 return -EBUSY;
4406 }
4407 }
4408 return 0;
4409}
4410
4411static void floppy_release_regions(int fdc)
4412{
4413 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4414}
4415
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416static int floppy_grab_irq_and_dma(void)
4417{
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004418 if (atomic_inc_return(&usage_count) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 return 0;
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004420
4421 /*
4422 * We might have scheduled a free_irq(), wait it to
4423 * drain first:
4424 */
4425 flush_scheduled_work();
4426
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 if (fd_request_irq()) {
4428 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4429 FLOPPY_IRQ);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004430 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431 return -1;
4432 }
4433 if (fd_request_dma()) {
4434 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4435 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004436 if (can_use_virtual_dma & 2)
4437 use_virtual_dma = can_use_virtual_dma = 1;
4438 if (!(can_use_virtual_dma & 1)) {
4439 fd_free_irq();
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004440 atomic_dec(&usage_count);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004441 return -1;
4442 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 }
4444
4445 for (fdc = 0; fdc < N_FDC; fdc++) {
4446 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004447 if (floppy_request_regions(fdc))
4448 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449 }
4450 }
4451 for (fdc = 0; fdc < N_FDC; fdc++) {
4452 if (FDCS->address != -1) {
4453 reset_fdc_info(1);
4454 fd_outb(FDCS->dor, FD_DOR);
4455 }
4456 }
4457 fdc = 0;
4458 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4459
4460 for (fdc = 0; fdc < N_FDC; fdc++)
4461 if (FDCS->address != -1)
4462 fd_outb(FDCS->dor, FD_DOR);
4463 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004464 * The driver will try and free resources and relies on us
4465 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 */
4467 fdc = 0;
4468 irqdma_allocated = 1;
4469 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004470cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 fd_free_irq();
4472 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004473 while (--fdc >= 0)
4474 floppy_release_regions(fdc);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004475 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476 return -1;
4477}
4478
4479static void floppy_release_irq_and_dma(void)
4480{
4481 int old_fdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482#ifndef __sparc__
4483 int drive;
4484#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 long tmpsize;
4486 unsigned long tmpaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004488 if (!atomic_dec_and_test(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489 return;
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004490
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 if (irqdma_allocated) {
4492 fd_disable_dma();
4493 fd_free_dma();
Ingo Molnar3e541a4a2006-07-03 00:24:23 -07004494 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495 irqdma_allocated = 0;
4496 }
4497 set_dor(0, ~0, 8);
4498#if N_FDC > 1
4499 set_dor(1, ~8, 0);
4500#endif
4501 floppy_enable_hlt();
4502
4503 if (floppy_track_buffer && max_buffer_sectors) {
4504 tmpsize = max_buffer_sectors * 1024;
4505 tmpaddr = (unsigned long)floppy_track_buffer;
4506 floppy_track_buffer = NULL;
4507 max_buffer_sectors = 0;
4508 buffer_min = buffer_max = -1;
4509 fd_dma_mem_free(tmpaddr, tmpsize);
4510 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511#ifndef __sparc__
4512 for (drive = 0; drive < N_FDC * 4; drive++)
4513 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004514 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515#endif
4516
4517 if (timer_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004518 pr_info("floppy timer still active:%s\n", timeout_message);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004520 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004521 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004522 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004523 old_fdc = fdc;
4524 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004525 if (FDCS->address != -1)
4526 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 fdc = old_fdc;
4528}
4529
4530#ifdef MODULE
4531
4532static char *floppy;
4533
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534static void __init parse_floppy_cfg_string(char *cfg)
4535{
4536 char *ptr;
4537
4538 while (*cfg) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004539 ptr = cfg;
4540 while (*cfg && *cfg != ' ' && *cfg != '\t')
4541 cfg++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 if (*cfg) {
4543 *cfg = '\0';
4544 cfg++;
4545 }
4546 if (*ptr)
4547 floppy_setup(ptr);
4548 }
4549}
4550
Jon Schindler7afea3b2008-04-29 00:59:21 -07004551static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552{
4553 if (floppy)
4554 parse_floppy_cfg_string(floppy);
4555 return floppy_init();
4556}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004557module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558
Jon Schindler7afea3b2008-04-29 00:59:21 -07004559static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560{
4561 int drive;
4562
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4564 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004565 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566
4567 for (drive = 0; drive < N_DRIVE; drive++) {
4568 del_timer_sync(&motor_off_timer[drive]);
4569
4570 if ((allowed_drive_mask & (1 << drive)) &&
4571 fdc_state[FDC(drive)].version != FDC_NONE) {
4572 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004573 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4574 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 }
4576 put_disk(disks[drive]);
Jens Axboe48821182010-09-22 09:32:36 +02004577 blk_cleanup_queue(disks[drive]->queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579
4580 del_timer_sync(&fd_timeout);
4581 del_timer_sync(&fd_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004583 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584 floppy_release_irq_and_dma();
4585
4586 /* eject disk, if any */
4587 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588}
Joe Perches48c8cee2010-03-10 15:20:45 -08004589
Jon Schindler7afea3b2008-04-29 00:59:21 -07004590module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591
4592module_param(floppy, charp, 0);
4593module_param(FLOPPY_IRQ, int, 0);
4594module_param(FLOPPY_DMA, int, 0);
4595MODULE_AUTHOR("Alain L. Knaff");
4596MODULE_SUPPORTED_DEVICE("fd");
4597MODULE_LICENSE("GPL");
4598
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004599/* This doesn't actually get used other than for module information */
4600static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004601 {"PNP0700", 0},
4602 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004603};
Joe Perches48c8cee2010-03-10 15:20:45 -08004604
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004605MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4606
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607#else
4608
4609__setup("floppy=", floppy_setup);
4610module_init(floppy_init)
4611#endif
4612
4613MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);