blob: b0b00d70c1669d6ef05993deb313dc516a23d552 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/block/floppy.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 * Copyright (C) 1993, 1994 Alain Knaff
6 * Copyright (C) 1998 Alan Cox
7 */
Jesper Juhl06f748c2007-10-16 23:30:57 -07008
Linus Torvalds1da177e2005-04-16 15:20:36 -07009/*
10 * 02.12.91 - Changed to static variables to indicate need for reset
11 * and recalibrate. This makes some things easier (output_byte reset
12 * checking etc), and means less interrupt jumping in case of errors,
13 * so the code is hopefully easier to understand.
14 */
15
16/*
17 * This file is certainly a mess. I've tried my best to get it working,
18 * but I don't like programming floppies, and I have only one anyway.
19 * Urgel. I should check for more errors, and do more graceful error
20 * recovery. Seems there are problems with several drives. I've tried to
21 * correct them. No promises.
22 */
23
24/*
25 * As with hd.c, all routines within this file can (and will) be called
26 * by interrupts, so extreme caution is needed. A hardware interrupt
27 * handler may not sleep, or a kernel panic will happen. Thus I cannot
28 * call "floppy-on" directly, but have to set a special timer interrupt
29 * etc.
30 */
31
32/*
33 * 28.02.92 - made track-buffering routines, based on the routines written
34 * by entropy@wintermute.wpi.edu (Lawrence Foard). Linus.
35 */
36
37/*
38 * Automatic floppy-detection and formatting written by Werner Almesberger
39 * (almesber@nessie.cs.id.ethz.ch), who also corrected some problems with
40 * the floppy-change signal detection.
41 */
42
43/*
44 * 1992/7/22 -- Hennus Bergman: Added better error reporting, fixed
45 * FDC data overrun bug, added some preliminary stuff for vertical
46 * recording support.
47 *
48 * 1992/9/17: Added DMA allocation & DMA functions. -- hhb.
49 *
50 * TODO: Errors are still not counted properly.
51 */
52
53/* 1992/9/20
54 * Modifications for ``Sector Shifting'' by Rob Hooft (hooft@chem.ruu.nl)
55 * modeled after the freeware MS-DOS program fdformat/88 V1.8 by
56 * Christoph H. Hochst\"atter.
57 * I have fixed the shift values to the ones I always use. Maybe a new
58 * ioctl() should be created to be able to modify them.
59 * There is a bug in the driver that makes it impossible to format a
60 * floppy as the first thing after bootup.
61 */
62
63/*
64 * 1993/4/29 -- Linus -- cleaned up the timer handling in the kernel, and
65 * this helped the floppy driver as well. Much cleaner, and still seems to
66 * work.
67 */
68
69/* 1994/6/24 --bbroad-- added the floppy table entries and made
70 * minor modifications to allow 2.88 floppies to be run.
71 */
72
73/* 1994/7/13 -- Paul Vojta -- modified the probing code to allow three or more
74 * disk types.
75 */
76
77/*
78 * 1994/8/8 -- Alain Knaff -- Switched to fdpatch driver: Support for bigger
79 * format bug fixes, but unfortunately some new bugs too...
80 */
81
82/* 1994/9/17 -- Koen Holtman -- added logging of physical floppy write
83 * errors to allow safe writing by specialized programs.
84 */
85
86/* 1995/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks
87 * by defining bit 1 of the "stretch" parameter to mean put sectors on the
88 * opposite side of the disk, leaving the sector IDs alone (i.e. Commodore's
89 * drives are "upside-down").
90 */
91
92/*
93 * 1995/8/26 -- Andreas Busse -- added Mips support.
94 */
95
96/*
97 * 1995/10/18 -- Ralf Baechle -- Portability cleanup; move machine dependent
98 * features to asm/floppy.h.
99 */
100
101/*
James Nelsonb88b0982005-11-08 16:52:12 +0100102 * 1998/1/21 -- Richard Gooch <rgooch@atnf.csiro.au> -- devfs support
103 */
104
105/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 * 1998/05/07 -- Russell King -- More portability cleanups; moved definition of
107 * interrupt and dma channel to asm/floppy.h. Cleaned up some formatting &
108 * use of '0' for NULL.
109 */
110
111/*
112 * 1998/06/07 -- Alan Cox -- Merged the 2.0.34 fixes for resource allocation
113 * failures.
114 */
115
116/*
117 * 1998/09/20 -- David Weinehall -- Added slow-down code for buggy PS/2-drives.
118 */
119
120/*
121 * 1999/08/13 -- Paul Slootman -- floppy stopped working on Alpha after 24
122 * days, 6 hours, 32 minutes and 32 seconds (i.e. MAXINT jiffies; ints were
123 * being used to store jiffies, which are unsigned longs).
124 */
125
126/*
127 * 2000/08/28 -- Arnaldo Carvalho de Melo <acme@conectiva.com.br>
128 * - get rid of check_region
129 * - s/suser/capable/
130 */
131
132/*
133 * 2001/08/26 -- Paul Gortmaker - fix insmod oops on machines with no
134 * floppy controller (lingering task on list after module is gone... boom.)
135 */
136
137/*
138 * 2002/02/07 -- Anton Altaparmakov - Fix io ports reservation to correct range
139 * (0x3f2-0x3f5, 0x3f7). This fix is a bit of a hack but the proper fix
140 * requires many non-obvious changes in arch dependent code.
141 */
142
143/* 2003/07/28 -- Daniele Bellucci <bellucda@tiscali.it>.
144 * Better audit of register_blkdev.
145 */
146
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147#undef FLOPPY_SILENT_DCL_CLEAR
148
149#define REALLY_SLOW_IO
150
151#define DEBUGT 2
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152
Joe Perches891eda82010-03-10 15:21:05 -0800153#define DPRINT(format, args...) \
154 pr_info("floppy%d: " format, current_drive, ##args)
155
156#define DCL_DEBUG /* debug disk change line */
Joe Perches87f530d2010-03-10 15:20:54 -0800157#ifdef DCL_DEBUG
158#define debug_dcl(test, fmt, args...) \
159 do { if ((test) & FD_DEBUG) DPRINT(fmt, ##args); } while (0)
160#else
161#define debug_dcl(test, fmt, args...) \
162 do { if (0) DPRINT(fmt, ##args); } while (0)
163#endif
164
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165/* do print messages for unexpected interrupts */
166static int print_unex = 1;
167#include <linux/module.h>
168#include <linux/sched.h>
169#include <linux/fs.h>
170#include <linux/kernel.h>
171#include <linux/timer.h>
172#include <linux/workqueue.h>
173#define FDPATCHES
174#include <linux/fdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175#include <linux/fd.h>
176#include <linux/hdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177#include <linux/errno.h>
178#include <linux/slab.h>
179#include <linux/mm.h>
180#include <linux/bio.h>
181#include <linux/string.h>
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800182#include <linux/jiffies.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183#include <linux/fcntl.h>
184#include <linux/delay.h>
185#include <linux/mc146818rtc.h> /* CMOS defines */
186#include <linux/ioport.h>
187#include <linux/interrupt.h>
188#include <linux/init.h>
Russell Kingd052d1b2005-10-29 19:07:23 +0100189#include <linux/platform_device.h>
Scott James Remnant83f9ef42009-04-02 16:56:47 -0700190#include <linux/mod_devicetable.h>
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800191#include <linux/mutex.h>
Joe Perchesd4937542010-03-10 15:20:44 -0800192#include <linux/io.h>
193#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195/*
196 * PS/2 floppies have much slower step rates than regular floppies.
197 * It's been recommended that take about 1/4 of the default speed
198 * in some more extreme cases.
199 */
Arnd Bergmann2a48fc02010-06-02 14:28:52 +0200200static DEFINE_MUTEX(floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201static int slow_floppy;
202
203#include <asm/dma.h>
204#include <asm/irq.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
206static int FLOPPY_IRQ = 6;
207static int FLOPPY_DMA = 2;
208static int can_use_virtual_dma = 2;
209/* =======
210 * can use virtual DMA:
211 * 0 = use of virtual DMA disallowed by config
212 * 1 = use of virtual DMA prescribed by config
213 * 2 = no virtual DMA preference configured. By default try hard DMA,
214 * but fall back on virtual DMA when not enough memory available
215 */
216
217static int use_virtual_dma;
218/* =======
219 * use virtual DMA
220 * 0 using hard DMA
221 * 1 using virtual DMA
222 * This variable is set to virtual when a DMA mem problem arises, and
223 * reset back in floppy_grab_irq_and_dma.
224 * It is not safe to reset it in other circumstances, because the floppy
225 * driver may have several buffers in use at once, and we do currently not
226 * record each buffers capabilities
227 */
228
229static DEFINE_SPINLOCK(floppy_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
231static unsigned short virtual_dma_port = 0x3f0;
David Howells7d12e782006-10-05 14:55:46 +0100232irqreturn_t floppy_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233static int set_dor(int fdc, char mask, char data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
235#define K_64 0x10000 /* 64KB */
236
237/* the following is the mask of allowed drives. By default units 2 and
238 * 3 of both floppy controllers are disabled, because switching on the
239 * motor of these drives causes system hangs on some PCI computers. drive
240 * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
241 * a drive is allowed.
242 *
243 * NOTE: This must come before we include the arch floppy header because
244 * some ports reference this variable from there. -DaveM
245 */
246
247static int allowed_drive_mask = 0x33;
248
249#include <asm/floppy.h>
250
251static int irqdma_allocated;
252
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253#include <linux/blkdev.h>
254#include <linux/blkpg.h>
255#include <linux/cdrom.h> /* for the compatibility eject ioctl */
256#include <linux/completion.h>
257
258static struct request *current_req;
Joe Perches48c8cee2010-03-10 15:20:45 -0800259static void do_fd_request(struct request_queue *q);
Jens Axboe48821182010-09-22 09:32:36 +0200260static int set_next_request(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
262#ifndef fd_get_dma_residue
263#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
264#endif
265
266/* Dma Memory related stuff */
267
268#ifndef fd_dma_mem_free
269#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
270#endif
271
272#ifndef fd_dma_mem_alloc
Joe Perches48c8cee2010-03-10 15:20:45 -0800273#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL, get_order(size))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274#endif
275
276static inline void fallback_on_nodma_alloc(char **addr, size_t l)
277{
278#ifdef FLOPPY_CAN_FALLBACK_ON_NODMA
279 if (*addr)
280 return; /* we have the memory */
281 if (can_use_virtual_dma != 2)
282 return; /* no fallback allowed */
Joe Perchesb46df352010-03-10 15:20:46 -0800283 pr_info("DMA memory shortage. Temporarily falling back on virtual DMA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 *addr = (char *)nodma_mem_alloc(l);
285#else
286 return;
287#endif
288}
289
290/* End dma memory related stuff */
291
292static unsigned long fake_change;
Joe Perches29f1c782010-03-10 15:21:00 -0800293static bool initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
Joe Perches48c8cee2010-03-10 15:20:45 -0800295#define ITYPE(x) (((x) >> 2) & 0x1f)
296#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
297#define UNIT(x) ((x) & 0x03) /* drive on fdc */
298#define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700299 /* reverse mapping from unit and fdc to drive */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
Joe Perches48c8cee2010-03-10 15:20:45 -0800302#define DP (&drive_params[current_drive])
303#define DRS (&drive_state[current_drive])
304#define DRWE (&write_errors[current_drive])
305#define FDCS (&fdc_state[fdc])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
Joe Perches48c8cee2010-03-10 15:20:45 -0800307#define UDP (&drive_params[drive])
308#define UDRS (&drive_state[drive])
309#define UDRWE (&write_errors[drive])
310#define UFDCS (&fdc_state[FDC(drive)])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
Joe Perches48c8cee2010-03-10 15:20:45 -0800312#define PH_HEAD(floppy, head) (((((floppy)->stretch & 2) >> 1) ^ head) << 2)
313#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
314
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315/* read/write */
Joe Perches48c8cee2010-03-10 15:20:45 -0800316#define COMMAND (raw_cmd->cmd[0])
317#define DR_SELECT (raw_cmd->cmd[1])
318#define TRACK (raw_cmd->cmd[2])
319#define HEAD (raw_cmd->cmd[3])
320#define SECTOR (raw_cmd->cmd[4])
321#define SIZECODE (raw_cmd->cmd[5])
322#define SECT_PER_TRACK (raw_cmd->cmd[6])
323#define GAP (raw_cmd->cmd[7])
324#define SIZECODE2 (raw_cmd->cmd[8])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325#define NR_RW 9
326
327/* format */
Joe Perches48c8cee2010-03-10 15:20:45 -0800328#define F_SIZECODE (raw_cmd->cmd[2])
329#define F_SECT_PER_TRACK (raw_cmd->cmd[3])
330#define F_GAP (raw_cmd->cmd[4])
331#define F_FILL (raw_cmd->cmd[5])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332#define NR_F 6
333
334/*
Joe Perches48c8cee2010-03-10 15:20:45 -0800335 * Maximum disk size (in kilobytes).
336 * This default is used whenever the current disk size is unknown.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 * [Now it is rather a minimum]
338 */
339#define MAX_DISK_SIZE 4 /* 3984 */
340
341/*
342 * globals used by 'result()'
343 */
344#define MAX_REPLIES 16
345static unsigned char reply_buffer[MAX_REPLIES];
Joe Perches891eda82010-03-10 15:21:05 -0800346static int inr; /* size of reply buffer, when called from interrupt */
Joe Perches48c8cee2010-03-10 15:20:45 -0800347#define ST0 (reply_buffer[0])
348#define ST1 (reply_buffer[1])
349#define ST2 (reply_buffer[2])
350#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
351#define R_TRACK (reply_buffer[3])
352#define R_HEAD (reply_buffer[4])
353#define R_SECTOR (reply_buffer[5])
354#define R_SIZECODE (reply_buffer[6])
355
356#define SEL_DLY (2 * HZ / 100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
358/*
359 * this struct defines the different floppy drive types.
360 */
361static struct {
362 struct floppy_drive_params params;
363 const char *name; /* name printed while booting */
364} default_drive_params[] = {
365/* NOTE: the time values in jiffies should be in msec!
366 CMOS drive type
367 | Maximum data rate supported by drive type
368 | | Head load time, msec
369 | | | Head unload time, msec (not used)
370 | | | | Step rate interval, usec
371 | | | | | Time needed for spinup time (jiffies)
372 | | | | | | Timeout for spinning down (jiffies)
373 | | | | | | | Spindown offset (where disk stops)
374 | | | | | | | | Select delay
375 | | | | | | | | | RPS
376 | | | | | | | | | | Max number of tracks
377 | | | | | | | | | | | Interrupt timeout
378 | | | | | | | | | | | | Max nonintlv. sectors
379 | | | | | | | | | | | | | -Max Errors- flags */
380{{0, 500, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 80, 3*HZ, 20, {3,1,2,0,2}, 0,
381 0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },
382
383{{1, 300, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 40, 3*HZ, 17, {3,1,2,0,2}, 0,
384 0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
385
386{{2, 500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0,
387 0, { 2, 5, 6,23,10,20,12, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/
388
389{{3, 250, 16, 16, 3000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
390 0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/
391
392{{4, 500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
393 0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/
394
395{{5, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
396 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
397
398{{6, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
399 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*/
400/* | --autodetected formats--- | | |
401 * read_track | | Name printed when booting
402 * | Native format
403 * Frequency of disk change checks */
404};
405
406static struct floppy_drive_params drive_params[N_DRIVE];
407static struct floppy_drive_struct drive_state[N_DRIVE];
408static struct floppy_write_errors write_errors[N_DRIVE];
409static struct timer_list motor_off_timer[N_DRIVE];
410static struct gendisk *disks[N_DRIVE];
411static struct block_device *opened_bdev[N_DRIVE];
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800412static DEFINE_MUTEX(open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
Jens Axboe48821182010-09-22 09:32:36 +0200414static int fdc_queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
416/*
417 * This struct defines the different floppy types.
418 *
419 * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
420 * types (e.g. 360kB diskette in 1.2MB drive, etc.). Bit 1 of 'stretch'
421 * tells if the disk is in Commodore 1581 format, which means side 0 sectors
422 * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
423 * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
424 * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
425 * side 0 is on physical side 0 (but with the misnamed sector IDs).
426 * 'stretch' should probably be renamed to something more general, like
Keith Wansbrough9e491842008-09-22 14:57:17 -0700427 * 'options'.
428 *
429 * Bits 2 through 9 of 'stretch' tell the number of the first sector.
430 * The LSB (bit 2) is flipped. For most disks, the first sector
431 * is 1 (represented by 0x00<<2). For some CP/M and music sampler
432 * disks (such as Ensoniq EPS 16plus) it is 0 (represented as 0x01<<2).
433 * For Amstrad CPC disks it is 0xC1 (represented as 0xC0<<2).
434 *
435 * Other parameters should be self-explanatory (see also setfdprm(8)).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 */
437/*
438 Size
439 | Sectors per track
440 | | Head
441 | | | Tracks
442 | | | | Stretch
443 | | | | | Gap 1 size
444 | | | | | | Data rate, | 0x40 for perp
445 | | | | | | | Spec1 (stepping rate, head unload
446 | | | | | | | | /fmt gap (gap2) */
447static struct floppy_struct floppy_type[32] = {
448 { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* 0 no testing */
449 { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360" }, /* 1 360KB PC */
450 { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" }, /* 2 1.2MB AT */
451 { 720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360" }, /* 3 360KB SS 3.5" */
452 { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720" }, /* 4 720KB 3.5" */
453 { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360" }, /* 5 360KB AT */
454 { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" }, /* 6 720KB AT */
455 { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /* 7 1.44MB 3.5" */
456 { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /* 8 2.88MB 3.5" */
457 { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" }, /* 9 3.12MB 3.5" */
458
459 { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */
460 { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */
461 { 820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410" }, /* 12 410KB 5.25" */
462 { 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820" }, /* 13 820KB 3.5" */
463 { 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" }, /* 14 1.48MB 5.25" */
464 { 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" }, /* 15 1.72MB 3.5" */
465 { 840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420" }, /* 16 420KB 5.25" */
466 { 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830" }, /* 17 830KB 3.5" */
467 { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" }, /* 18 1.49MB 5.25" */
468 { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5" */
469
470 { 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880" }, /* 20 880KB 5.25" */
471 { 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5" */
472 { 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5" */
473 { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25" */
474 { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5" */
475 { 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5" */
476 { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5" */
477 { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5" */
478 { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5" */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5" */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700480
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */
482 { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */
483};
484
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485#define SECTSIZE (_FD_SECTSIZE(*floppy))
486
487/* Auto-detection: Disk type used until the next media change occurs. */
488static struct floppy_struct *current_type[N_DRIVE];
489
490/*
491 * User-provided type information. current_type points to
492 * the respective entry of this array.
493 */
494static struct floppy_struct user_params[N_DRIVE];
495
496static sector_t floppy_sizes[256];
497
Hannes Reinecke94fd0db2005-07-15 10:09:25 +0200498static char floppy_device_name[] = "floppy";
499
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500/*
501 * The driver is trying to determine the correct media format
502 * while probing is set. rw_interrupt() clears it after a
503 * successful access.
504 */
505static int probing;
506
507/* Synchronization of FDC access. */
Joe Perches48c8cee2010-03-10 15:20:45 -0800508#define FD_COMMAND_NONE -1
509#define FD_COMMAND_ERROR 2
510#define FD_COMMAND_OKAY 3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
512static volatile int command_status = FD_COMMAND_NONE;
513static unsigned long fdc_busy;
514static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
515static DECLARE_WAIT_QUEUE_HEAD(command_done);
516
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517/* Errors during formatting are counted here. */
518static int format_errors;
519
520/* Format request descriptor. */
521static struct format_descr format_req;
522
523/*
524 * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
525 * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
526 * H is head unload time (1=16ms, 2=32ms, etc)
527 */
528
529/*
530 * Track buffer
531 * Because these are written to by the DMA controller, they must
532 * not contain a 64k byte boundary crossing, or data will be
533 * corrupted/lost.
534 */
535static char *floppy_track_buffer;
536static int max_buffer_sectors;
537
538static int *errors;
Jesper Juhl06f748c2007-10-16 23:30:57 -0700539typedef void (*done_f)(int);
Stephen Hemminger3b06c212010-07-20 20:09:00 -0600540static const struct cont_t {
Joe Perches48c8cee2010-03-10 15:20:45 -0800541 void (*interrupt)(void);
542 /* this is called after the interrupt of the
543 * main command */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700544 void (*redo)(void); /* this is called to retry the operation */
545 void (*error)(void); /* this is called to tally an error */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 done_f done; /* this is called to say if the operation has
547 * succeeded/failed */
548} *cont;
549
550static void floppy_ready(void);
551static void floppy_start(void);
552static void process_fd_request(void);
553static void recalibrate_floppy(void);
554static void floppy_shutdown(unsigned long);
555
Philippe De Muyter5a74db02009-02-18 14:48:36 -0800556static int floppy_request_regions(int);
557static void floppy_release_regions(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558static int floppy_grab_irq_and_dma(void);
559static void floppy_release_irq_and_dma(void);
560
561/*
562 * The "reset" variable should be tested whenever an interrupt is scheduled,
563 * after the commands have been sent. This is to ensure that the driver doesn't
564 * get wedged when the interrupt doesn't come because of a failed command.
565 * reset doesn't need to be tested before sending commands, because
566 * output_byte is automatically disabled when reset is set.
567 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568static void reset_fdc(void);
569
570/*
571 * These are global variables, as that's the easiest way to give
572 * information to interrupts. They are the data used for the current
573 * request.
574 */
Joe Perches48c8cee2010-03-10 15:20:45 -0800575#define NO_TRACK -1
576#define NEED_1_RECAL -2
577#define NEED_2_RECAL -3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
Stephen Hemminger575cfc62010-06-15 13:21:11 +0200579static atomic_t usage_count = ATOMIC_INIT(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
581/* buffer related variables */
582static int buffer_track = -1;
583static int buffer_drive = -1;
584static int buffer_min = -1;
585static int buffer_max = -1;
586
587/* fdc related variables, should end up in a struct */
588static struct floppy_fdc_state fdc_state[N_FDC];
589static int fdc; /* current fdc */
590
591static struct floppy_struct *_floppy = floppy_type;
592static unsigned char current_drive;
593static long current_count_sectors;
594static unsigned char fsector_t; /* sector in track */
595static unsigned char in_sector_offset; /* offset within physical sector,
596 * expressed in units of 512 bytes */
597
Pekka Enberg2b51dca2010-11-08 14:44:34 +0100598static inline bool drive_no_geom(int drive)
599{
600 return !current_type[drive] && !ITYPE(UDRS->fd_device);
601}
602
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603#ifndef fd_eject
604static inline int fd_eject(int drive)
605{
606 return -EINVAL;
607}
608#endif
609
610/*
611 * Debugging
612 * =========
613 */
614#ifdef DEBUGT
615static long unsigned debugtimer;
616
617static inline void set_debugt(void)
618{
619 debugtimer = jiffies;
620}
621
Joe Perchesded28632010-03-10 15:21:09 -0800622static inline void debugt(const char *func, const char *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623{
624 if (DP->flags & DEBUGT)
Joe Perchesded28632010-03-10 15:21:09 -0800625 pr_info("%s:%s dtime=%lu\n", func, msg, jiffies - debugtimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626}
627#else
628static inline void set_debugt(void) { }
Joe Perchesded28632010-03-10 15:21:09 -0800629static inline void debugt(const char *func, const char *msg) { }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630#endif /* DEBUGT */
631
Joe Perchesa0a52d62010-03-10 15:20:52 -0800632typedef void (*timeout_fn)(unsigned long);
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700633static DEFINE_TIMER(fd_timeout, floppy_shutdown, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634
635static const char *timeout_message;
636
Joe Perches275176b2010-03-10 15:21:06 -0800637static void is_alive(const char *func, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638{
639 /* this routine checks whether the floppy driver is "alive" */
Joe Perchesc5297302010-03-10 15:20:58 -0800640 if (test_bit(0, &fdc_busy) && command_status < 2 &&
641 !timer_pending(&fd_timeout)) {
Joe Perches275176b2010-03-10 15:21:06 -0800642 DPRINT("%s: timeout handler died. %s\n", func, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 }
644}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645
Joe Perches48c8cee2010-03-10 15:20:45 -0800646static void (*do_floppy)(void) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648#define OLOGSIZE 20
649
Joe Perches48c8cee2010-03-10 15:20:45 -0800650static void (*lasthandler)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651static unsigned long interruptjiffies;
652static unsigned long resultjiffies;
653static int resultsize;
654static unsigned long lastredo;
655
656static struct output_log {
657 unsigned char data;
658 unsigned char status;
659 unsigned long jiffies;
660} output_log[OLOGSIZE];
661
662static int output_log_pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
664#define current_reqD -1
665#define MAXTIMEOUT -2
666
Joe Perches73507e62010-03-10 15:21:03 -0800667static void __reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668{
669 if (drive == current_reqD)
670 drive = current_drive;
671 del_timer(&fd_timeout);
Eric Sesterhenn / Snakebyte4acb3e22007-05-23 13:58:15 -0700672 if (drive < 0 || drive >= N_DRIVE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 fd_timeout.expires = jiffies + 20UL * HZ;
674 drive = 0;
675 } else
676 fd_timeout.expires = jiffies + UDP->timeout;
677 add_timer(&fd_timeout);
Joe Perchesa81ee542010-03-10 15:20:46 -0800678 if (UDP->flags & FD_DEBUG)
Joe Perches73507e62010-03-10 15:21:03 -0800679 DPRINT("reschedule timeout %s\n", message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 timeout_message = message;
681}
682
Joe Perches73507e62010-03-10 15:21:03 -0800683static void reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684{
685 unsigned long flags;
686
687 spin_lock_irqsave(&floppy_lock, flags);
Joe Perches73507e62010-03-10 15:21:03 -0800688 __reschedule_timeout(drive, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 spin_unlock_irqrestore(&floppy_lock, flags);
690}
691
Joe Perches48c8cee2010-03-10 15:20:45 -0800692#define INFBOUND(a, b) (a) = max_t(int, a, b)
693#define SUPBOUND(a, b) (a) = min_t(int, a, b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
695/*
696 * Bottom half floppy driver.
697 * ==========================
698 *
699 * This part of the file contains the code talking directly to the hardware,
700 * and also the main service loop (seek-configure-spinup-command)
701 */
702
703/*
704 * disk change.
705 * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
706 * and the last_checked date.
707 *
708 * last_checked is the date of the last check which showed 'no disk change'
709 * FD_DISK_CHANGE is set under two conditions:
710 * 1. The floppy has been changed after some i/o to that floppy already
711 * took place.
712 * 2. No floppy disk is in the drive. This is done in order to ensure that
713 * requests are quickly flushed in case there is no disk in the drive. It
714 * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
715 * the drive.
716 *
717 * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
718 * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
719 * each seek. If a disk is present, the disk change line should also be
720 * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
721 * change line is set, this means either that no disk is in the drive, or
722 * that it has been removed since the last seek.
723 *
724 * This means that we really have a third possibility too:
725 * The floppy has been changed after the last seek.
726 */
727
728static int disk_change(int drive)
729{
730 int fdc = FDC(drive);
Jesper Juhl06f748c2007-10-16 23:30:57 -0700731
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800732 if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 DPRINT("WARNING disk change called early\n");
734 if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
735 (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
736 DPRINT("probing disk change on unselected drive\n");
737 DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
738 (unsigned int)FDCS->dor);
739 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740
Joe Perches87f530d2010-03-10 15:20:54 -0800741 debug_dcl(UDP->flags,
742 "checking disk change line for drive %d\n", drive);
743 debug_dcl(UDP->flags, "jiffies=%lu\n", jiffies);
744 debug_dcl(UDP->flags, "disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
745 debug_dcl(UDP->flags, "flags=%lx\n", UDRS->flags);
746
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 if (UDP->flags & FD_BROKEN_DCL)
Joe Perchese0298532010-03-10 15:20:55 -0800748 return test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
Joe Perchese0298532010-03-10 15:20:55 -0800750 set_bit(FD_VERIFY_BIT, &UDRS->flags);
751 /* verify write protection */
752
753 if (UDRS->maxblock) /* mark it changed */
754 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755
756 /* invalidate its geometry */
757 if (UDRS->keep_data >= 0) {
758 if ((UDP->flags & FTD_MSG) &&
759 current_type[drive] != NULL)
Joe Perches891eda82010-03-10 15:21:05 -0800760 DPRINT("Disk type is undefined after disk change\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 current_type[drive] = NULL;
762 floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
763 }
764
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 return 1;
766 } else {
767 UDRS->last_checked = jiffies;
Joe Perchese0298532010-03-10 15:20:55 -0800768 clear_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 }
770 return 0;
771}
772
773static inline int is_selected(int dor, int unit)
774{
775 return ((dor & (0x10 << unit)) && (dor & 3) == unit);
776}
777
Joe Perches57584c52010-03-10 15:21:00 -0800778static bool is_ready_state(int status)
779{
780 int state = status & (STATUS_READY | STATUS_DIR | STATUS_DMA);
781 return state == STATUS_READY;
782}
783
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784static int set_dor(int fdc, char mask, char data)
785{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700786 unsigned char unit;
787 unsigned char drive;
788 unsigned char newdor;
789 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
791 if (FDCS->address == -1)
792 return -1;
793
794 olddor = FDCS->dor;
795 newdor = (olddor & mask) | data;
796 if (newdor != olddor) {
797 unit = olddor & 0x3;
798 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
799 drive = REVDRIVE(fdc, unit);
Joe Perches87f530d2010-03-10 15:20:54 -0800800 debug_dcl(UDP->flags,
801 "calling disk change from set_dor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 disk_change(drive);
803 }
804 FDCS->dor = newdor;
805 fd_outb(newdor, FD_DOR);
806
807 unit = newdor & 0x3;
808 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
809 drive = REVDRIVE(fdc, unit);
810 UDRS->select_date = jiffies;
811 }
812 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 return olddor;
814}
815
816static void twaddle(void)
817{
818 if (DP->select_delay)
819 return;
820 fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
821 fd_outb(FDCS->dor, FD_DOR);
822 DRS->select_date = jiffies;
823}
824
Joe Perches57584c52010-03-10 15:21:00 -0800825/*
826 * Reset all driver information about the current fdc.
827 * This is needed after a reset, and after a raw command.
828 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829static void reset_fdc_info(int mode)
830{
831 int drive;
832
833 FDCS->spec1 = FDCS->spec2 = -1;
834 FDCS->need_configure = 1;
835 FDCS->perp_mode = 1;
836 FDCS->rawcmd = 0;
837 for (drive = 0; drive < N_DRIVE; drive++)
838 if (FDC(drive) == fdc && (mode || UDRS->track != NEED_1_RECAL))
839 UDRS->track = NEED_2_RECAL;
840}
841
842/* selects the fdc and drive, and enables the fdc's input/dma. */
843static void set_fdc(int drive)
844{
845 if (drive >= 0 && drive < N_DRIVE) {
846 fdc = FDC(drive);
847 current_drive = drive;
848 }
849 if (fdc != 1 && fdc != 0) {
Joe Perchesb46df352010-03-10 15:20:46 -0800850 pr_info("bad fdc value\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 return;
852 }
853 set_dor(fdc, ~0, 8);
854#if N_FDC > 1
855 set_dor(1 - fdc, ~8, 0);
856#endif
857 if (FDCS->rawcmd == 2)
858 reset_fdc_info(1);
859 if (fd_inb(FD_STATUS) != STATUS_READY)
860 FDCS->reset = 1;
861}
862
863/* locks the driver */
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200864static int lock_fdc(int drive, bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865{
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200866 if (WARN(atomic_read(&usage_count) == 0,
867 "Trying to lock fdc while usage count=0\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200870 if (wait_event_interruptible(fdc_wait, !test_and_set_bit(0, &fdc_busy)))
871 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 command_status = FD_COMMAND_NONE;
874
Joe Perches73507e62010-03-10 15:21:03 -0800875 __reschedule_timeout(drive, "lock fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 set_fdc(drive);
877 return 0;
878}
879
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880/* unlocks the driver */
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +0200881static void unlock_fdc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882{
883 unsigned long flags;
884
885 raw_cmd = NULL;
886 if (!test_bit(0, &fdc_busy))
887 DPRINT("FDC access conflict!\n");
888
889 if (do_floppy)
Joe Perches1ebddd82010-03-10 15:21:07 -0800890 DPRINT("device interrupt still active at FDC release: %pf!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 do_floppy);
892 command_status = FD_COMMAND_NONE;
893 spin_lock_irqsave(&floppy_lock, flags);
894 del_timer(&fd_timeout);
895 cont = NULL;
896 clear_bit(0, &fdc_busy);
Jens Axboe48821182010-09-22 09:32:36 +0200897 if (current_req || set_next_request())
898 do_fd_request(current_req->q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 spin_unlock_irqrestore(&floppy_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 wake_up(&fdc_wait);
901}
902
903/* switches the motor off after a given timeout */
904static void motor_off_callback(unsigned long nr)
905{
906 unsigned char mask = ~(0x10 << UNIT(nr));
907
908 set_dor(FDC(nr), mask, 0);
909}
910
911/* schedules motor off */
912static void floppy_off(unsigned int drive)
913{
914 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700915 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
917 if (!(FDCS->dor & (0x10 << UNIT(drive))))
918 return;
919
920 del_timer(motor_off_timer + drive);
921
922 /* make spindle stop in a position which minimizes spinup time
923 * next time */
924 if (UDP->rps) {
925 delta = jiffies - UDRS->first_read_date + HZ -
926 UDP->spindown_offset;
927 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
928 motor_off_timer[drive].expires =
929 jiffies + UDP->spindown - delta;
930 }
931 add_timer(motor_off_timer + drive);
932}
933
934/*
935 * cycle through all N_DRIVE floppy drives, for disk change testing.
936 * stopping at current drive. This is done before any long operation, to
937 * be sure to have up to date disk change information.
938 */
939static void scandrives(void)
940{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700941 int i;
942 int drive;
943 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944
945 if (DP->select_delay)
946 return;
947
948 saved_drive = current_drive;
949 for (i = 0; i < N_DRIVE; i++) {
950 drive = (saved_drive + i + 1) % N_DRIVE;
951 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
952 continue; /* skip closed drives */
953 set_fdc(drive);
954 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
955 (0x10 << UNIT(drive))))
956 /* switch the motor off again, if it was off to
957 * begin with */
958 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
959 }
960 set_fdc(saved_drive);
961}
962
963static void empty(void)
964{
965}
966
David Howells65f27f32006-11-22 14:55:48 +0000967static DECLARE_WORK(floppy_work, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968
Joe Perches48c8cee2010-03-10 15:20:45 -0800969static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970{
David Howells65f27f32006-11-22 14:55:48 +0000971 PREPARE_WORK(&floppy_work, (work_func_t)handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 schedule_work(&floppy_work);
973}
974
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700975static DEFINE_TIMER(fd_timer, NULL, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
977static void cancel_activity(void)
978{
979 unsigned long flags;
980
981 spin_lock_irqsave(&floppy_lock, flags);
982 do_floppy = NULL;
David Howells65f27f32006-11-22 14:55:48 +0000983 PREPARE_WORK(&floppy_work, (work_func_t)empty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 del_timer(&fd_timer);
985 spin_unlock_irqrestore(&floppy_lock, flags);
986}
987
988/* this function makes sure that the disk stays in the drive during the
989 * transfer */
990static void fd_watchdog(void)
991{
Joe Perches87f530d2010-03-10 15:20:54 -0800992 debug_dcl(DP->flags, "calling disk change from watchdog\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
994 if (disk_change(current_drive)) {
995 DPRINT("disk removed during i/o\n");
996 cancel_activity();
997 cont->done(0);
998 reset_fdc();
999 } else {
1000 del_timer(&fd_timer);
Joe Perchesa0a52d62010-03-10 15:20:52 -08001001 fd_timer.function = (timeout_fn)fd_watchdog;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 fd_timer.expires = jiffies + HZ / 10;
1003 add_timer(&fd_timer);
1004 }
1005}
1006
1007static void main_command_interrupt(void)
1008{
1009 del_timer(&fd_timer);
1010 cont->interrupt();
1011}
1012
1013/* waits for a delay (spinup or select) to pass */
1014static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
1015{
1016 if (FDCS->reset) {
1017 reset_fdc(); /* do the reset during sleep to win time
1018 * if we don't need to sleep, it's a good
1019 * occasion anyways */
1020 return 1;
1021 }
1022
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001023 if (time_before(jiffies, delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 del_timer(&fd_timer);
1025 fd_timer.function = function;
1026 fd_timer.expires = delay;
1027 add_timer(&fd_timer);
1028 return 1;
1029 }
1030 return 0;
1031}
1032
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033static void setup_DMA(void)
1034{
1035 unsigned long f;
1036
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 if (raw_cmd->length == 0) {
1038 int i;
1039
Joe Perchesb46df352010-03-10 15:20:46 -08001040 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001042 pr_cont("%x,", raw_cmd->cmd[i]);
1043 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 cont->done(0);
1045 FDCS->reset = 1;
1046 return;
1047 }
1048 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001049 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 cont->done(0);
1051 FDCS->reset = 1;
1052 return;
1053 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 f = claim_dma_lock();
1055 fd_disable_dma();
1056#ifdef fd_dma_setup
1057 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1058 (raw_cmd->flags & FD_RAW_READ) ?
1059 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1060 release_dma_lock(f);
1061 cont->done(0);
1062 FDCS->reset = 1;
1063 return;
1064 }
1065 release_dma_lock(f);
1066#else
1067 fd_clear_dma_ff();
1068 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1069 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1070 DMA_MODE_READ : DMA_MODE_WRITE);
1071 fd_set_dma_addr(raw_cmd->kernel_data);
1072 fd_set_dma_count(raw_cmd->length);
1073 virtual_dma_port = FDCS->address;
1074 fd_enable_dma();
1075 release_dma_lock(f);
1076#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077}
1078
1079static void show_floppy(void);
1080
1081/* waits until the fdc becomes ready */
1082static int wait_til_ready(void)
1083{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001084 int status;
1085 int counter;
1086
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 if (FDCS->reset)
1088 return -1;
1089 for (counter = 0; counter < 10000; counter++) {
1090 status = fd_inb(FD_STATUS);
1091 if (status & STATUS_READY)
1092 return status;
1093 }
Joe Perches29f1c782010-03-10 15:21:00 -08001094 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1096 show_floppy();
1097 }
1098 FDCS->reset = 1;
1099 return -1;
1100}
1101
1102/* sends a command byte to the fdc */
1103static int output_byte(char byte)
1104{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001105 int status = wait_til_ready();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001107 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001109
1110 if (is_ready_state(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 fd_outb(byte, FD_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 output_log[output_log_pos].data = byte;
1113 output_log[output_log_pos].status = status;
1114 output_log[output_log_pos].jiffies = jiffies;
1115 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 return 0;
1117 }
1118 FDCS->reset = 1;
Joe Perches29f1c782010-03-10 15:21:00 -08001119 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1121 byte, fdc, status);
1122 show_floppy();
1123 }
1124 return -1;
1125}
1126
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127/* gets the response from the fdc */
1128static int result(void)
1129{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001130 int i;
1131 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
1133 for (i = 0; i < MAX_REPLIES; i++) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001134 status = wait_til_ready();
1135 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 break;
1137 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1138 if ((status & ~STATUS_BUSY) == STATUS_READY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 resultjiffies = jiffies;
1140 resultsize = i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 return i;
1142 }
1143 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1144 reply_buffer[i] = fd_inb(FD_DATA);
1145 else
1146 break;
1147 }
Joe Perches29f1c782010-03-10 15:21:00 -08001148 if (initialized) {
1149 DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1150 fdc, status, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 show_floppy();
1152 }
1153 FDCS->reset = 1;
1154 return -1;
1155}
1156
1157#define MORE_OUTPUT -2
1158/* does the fdc need more output? */
1159static int need_more_output(void)
1160{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001161 int status = wait_til_ready();
Jesper Juhl06f748c2007-10-16 23:30:57 -07001162
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001163 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001165
1166 if (is_ready_state(status))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 return MORE_OUTPUT;
Joe Perches57584c52010-03-10 15:21:00 -08001168
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 return result();
1170}
1171
1172/* Set perpendicular mode as required, based on data rate, if supported.
1173 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1174 */
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02001175static void perpendicular_mode(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176{
1177 unsigned char perp_mode;
1178
1179 if (raw_cmd->rate & 0x40) {
1180 switch (raw_cmd->rate & 3) {
1181 case 0:
1182 perp_mode = 2;
1183 break;
1184 case 3:
1185 perp_mode = 3;
1186 break;
1187 default:
1188 DPRINT("Invalid data rate for perpendicular mode!\n");
1189 cont->done(0);
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001190 FDCS->reset = 1;
1191 /*
1192 * convenient way to return to
1193 * redo without too much hassle
1194 * (deep stack et al.)
1195 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 return;
1197 }
1198 } else
1199 perp_mode = 0;
1200
1201 if (FDCS->perp_mode == perp_mode)
1202 return;
1203 if (FDCS->version >= FDC_82077_ORIG) {
1204 output_byte(FD_PERPENDICULAR);
1205 output_byte(perp_mode);
1206 FDCS->perp_mode = perp_mode;
1207 } else if (perp_mode) {
1208 DPRINT("perpendicular mode not supported by this FDC.\n");
1209 }
1210} /* perpendicular_mode */
1211
1212static int fifo_depth = 0xa;
1213static int no_fifo;
1214
1215static int fdc_configure(void)
1216{
1217 /* Turn on FIFO */
1218 output_byte(FD_CONFIGURE);
1219 if (need_more_output() != MORE_OUTPUT)
1220 return 0;
1221 output_byte(0);
1222 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1223 output_byte(0); /* pre-compensation from track
1224 0 upwards */
1225 return 1;
1226}
1227
1228#define NOMINAL_DTR 500
1229
1230/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1231 * head load time, and DMA disable flag to values needed by floppy.
1232 *
1233 * The value "dtr" is the data transfer rate in Kbps. It is needed
1234 * to account for the data rate-based scaling done by the 82072 and 82077
1235 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1236 * 8272a).
1237 *
1238 * Note that changing the data transfer rate has a (probably deleterious)
1239 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1240 * fdc_specify is called again after each data transfer rate
1241 * change.
1242 *
1243 * srt: 1000 to 16000 in microseconds
1244 * hut: 16 to 240 milliseconds
1245 * hlt: 2 to 254 milliseconds
1246 *
1247 * These values are rounded up to the next highest available delay time.
1248 */
1249static void fdc_specify(void)
1250{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001251 unsigned char spec1;
1252 unsigned char spec2;
1253 unsigned long srt;
1254 unsigned long hlt;
1255 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 unsigned long dtr = NOMINAL_DTR;
1257 unsigned long scale_dtr = NOMINAL_DTR;
1258 int hlt_max_code = 0x7f;
1259 int hut_max_code = 0xf;
1260
1261 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1262 fdc_configure();
1263 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 }
1265
1266 switch (raw_cmd->rate & 0x03) {
1267 case 3:
1268 dtr = 1000;
1269 break;
1270 case 1:
1271 dtr = 300;
1272 if (FDCS->version >= FDC_82078) {
1273 /* chose the default rate table, not the one
1274 * where 1 = 2 Mbps */
1275 output_byte(FD_DRIVESPEC);
1276 if (need_more_output() == MORE_OUTPUT) {
1277 output_byte(UNIT(current_drive));
1278 output_byte(0xc0);
1279 }
1280 }
1281 break;
1282 case 2:
1283 dtr = 250;
1284 break;
1285 }
1286
1287 if (FDCS->version >= FDC_82072) {
1288 scale_dtr = dtr;
1289 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1290 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1291 }
1292
1293 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001294 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001295 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001297
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 SUPBOUND(srt, 0xf);
1299 INFBOUND(srt, 0);
1300
Julia Lawall061837b2008-09-22 14:57:16 -07001301 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 if (hlt < 0x01)
1303 hlt = 0x01;
1304 else if (hlt > 0x7f)
1305 hlt = hlt_max_code;
1306
Julia Lawall061837b2008-09-22 14:57:16 -07001307 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 if (hut < 0x1)
1309 hut = 0x1;
1310 else if (hut > 0xf)
1311 hut = hut_max_code;
1312
1313 spec1 = (srt << 4) | hut;
1314 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1315
1316 /* If these parameters did not change, just return with success */
1317 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1318 /* Go ahead and set spec1 and spec2 */
1319 output_byte(FD_SPECIFY);
1320 output_byte(FDCS->spec1 = spec1);
1321 output_byte(FDCS->spec2 = spec2);
1322 }
1323} /* fdc_specify */
1324
1325/* Set the FDC's data transfer rate on behalf of the specified drive.
1326 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1327 * of the specify command (i.e. using the fdc_specify function).
1328 */
1329static int fdc_dtr(void)
1330{
1331 /* If data rate not already set to desired value, set it. */
1332 if ((raw_cmd->rate & 3) == FDCS->dtr)
1333 return 0;
1334
1335 /* Set dtr */
1336 fd_outb(raw_cmd->rate & 3, FD_DCR);
1337
1338 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1339 * need a stabilization period of several milliseconds to be
1340 * enforced after data rate changes before R/W operations.
1341 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1342 */
1343 FDCS->dtr = raw_cmd->rate & 3;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001344 return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
1345 (timeout_fn)floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346} /* fdc_dtr */
1347
1348static void tell_sector(void)
1349{
Joe Perchesb46df352010-03-10 15:20:46 -08001350 pr_cont(": track %d, head %d, sector %d, size %d",
1351 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352} /* tell_sector */
1353
Joe Perchesb46df352010-03-10 15:20:46 -08001354static void print_errors(void)
1355{
1356 DPRINT("");
1357 if (ST0 & ST0_ECE) {
1358 pr_cont("Recalibrate failed!");
1359 } else if (ST2 & ST2_CRC) {
1360 pr_cont("data CRC error");
1361 tell_sector();
1362 } else if (ST1 & ST1_CRC) {
1363 pr_cont("CRC error");
1364 tell_sector();
1365 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1366 (ST2 & ST2_MAM)) {
1367 if (!probing) {
1368 pr_cont("sector not found");
1369 tell_sector();
1370 } else
1371 pr_cont("probe failed...");
1372 } else if (ST2 & ST2_WC) { /* seek error */
1373 pr_cont("wrong cylinder");
1374 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1375 pr_cont("bad cylinder");
1376 } else {
1377 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1378 ST0, ST1, ST2);
1379 tell_sector();
1380 }
1381 pr_cont("\n");
1382}
1383
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384/*
1385 * OK, this error interpreting routine is called after a
1386 * DMA read/write has succeeded
1387 * or failed, so we check the results, and copy any buffers.
1388 * hhb: Added better error reporting.
1389 * ak: Made this into a separate routine.
1390 */
1391static int interpret_errors(void)
1392{
1393 char bad;
1394
1395 if (inr != 7) {
Joe Perches891eda82010-03-10 15:21:05 -08001396 DPRINT("-- FDC reply error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 FDCS->reset = 1;
1398 return 1;
1399 }
1400
1401 /* check IC to find cause of interrupt */
1402 switch (ST0 & ST0_INTR) {
1403 case 0x40: /* error occurred during command execution */
1404 if (ST1 & ST1_EOC)
1405 return 0; /* occurs with pseudo-DMA */
1406 bad = 1;
1407 if (ST1 & ST1_WP) {
1408 DPRINT("Drive is write protected\n");
Joe Perchese0298532010-03-10 15:20:55 -08001409 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 cont->done(0);
1411 bad = 2;
1412 } else if (ST1 & ST1_ND) {
Joe Perchese0298532010-03-10 15:20:55 -08001413 set_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 } else if (ST1 & ST1_OR) {
1415 if (DP->flags & FTD_MSG)
1416 DPRINT("Over/Underrun - retrying\n");
1417 bad = 0;
1418 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001419 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 }
1421 if (ST2 & ST2_WC || ST2 & ST2_BC)
1422 /* wrong cylinder => recal */
1423 DRS->track = NEED_2_RECAL;
1424 return bad;
1425 case 0x80: /* invalid command given */
1426 DPRINT("Invalid FDC command given!\n");
1427 cont->done(0);
1428 return 2;
1429 case 0xc0:
1430 DPRINT("Abnormal termination caused by polling\n");
1431 cont->error();
1432 return 2;
1433 default: /* (0) Normal command termination */
1434 return 0;
1435 }
1436}
1437
1438/*
1439 * This routine is called when everything should be correctly set up
1440 * for the transfer (i.e. floppy motor is on, the correct floppy is
1441 * selected, and the head is sitting on the right track).
1442 */
1443static void setup_rw_floppy(void)
1444{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001445 int i;
1446 int r;
1447 int flags;
1448 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 unsigned long ready_date;
1450 timeout_fn function;
1451
1452 flags = raw_cmd->flags;
1453 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1454 flags |= FD_RAW_INTR;
1455
1456 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1457 ready_date = DRS->spinup_date + DP->spinup;
1458 /* If spinup will take a long time, rerun scandrives
1459 * again just before spinup completion. Beware that
1460 * after scandrives, we must again wait for selection.
1461 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001462 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 ready_date -= DP->select_delay;
Joe Perchesa0a52d62010-03-10 15:20:52 -08001464 function = (timeout_fn)floppy_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 } else
Joe Perchesa0a52d62010-03-10 15:20:52 -08001466 function = (timeout_fn)setup_rw_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467
1468 /* wait until the floppy is spinning fast enough */
1469 if (fd_wait_for_completion(ready_date, function))
1470 return;
1471 }
1472 dflags = DRS->flags;
1473
1474 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1475 setup_DMA();
1476
1477 if (flags & FD_RAW_INTR)
1478 do_floppy = main_command_interrupt;
1479
1480 r = 0;
1481 for (i = 0; i < raw_cmd->cmd_count; i++)
1482 r |= output_byte(raw_cmd->cmd[i]);
1483
Joe Perchesded28632010-03-10 15:21:09 -08001484 debugt(__func__, "rw_command");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485
1486 if (r) {
1487 cont->error();
1488 reset_fdc();
1489 return;
1490 }
1491
1492 if (!(flags & FD_RAW_INTR)) {
1493 inr = result();
1494 cont->interrupt();
1495 } else if (flags & FD_RAW_NEED_DISK)
1496 fd_watchdog();
1497}
1498
1499static int blind_seek;
1500
1501/*
1502 * This is the routine called after every seek (or recalibrate) interrupt
1503 * from the floppy controller.
1504 */
1505static void seek_interrupt(void)
1506{
Joe Perchesded28632010-03-10 15:21:09 -08001507 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1509 DPRINT("seek failed\n");
1510 DRS->track = NEED_2_RECAL;
1511 cont->error();
1512 cont->redo();
1513 return;
1514 }
1515 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
Joe Perches87f530d2010-03-10 15:20:54 -08001516 debug_dcl(DP->flags,
1517 "clearing NEWCHANGE flag because of effective seek\n");
1518 debug_dcl(DP->flags, "jiffies=%lu\n", jiffies);
Joe Perchese0298532010-03-10 15:20:55 -08001519 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
1520 /* effective seek */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 DRS->select_date = jiffies;
1522 }
1523 DRS->track = ST1;
1524 floppy_ready();
1525}
1526
1527static void check_wp(void)
1528{
Joe Perchese0298532010-03-10 15:20:55 -08001529 if (test_bit(FD_VERIFY_BIT, &DRS->flags)) {
1530 /* check write protection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 output_byte(FD_GETSTATUS);
1532 output_byte(UNIT(current_drive));
1533 if (result() != 1) {
1534 FDCS->reset = 1;
1535 return;
1536 }
Joe Perchese0298532010-03-10 15:20:55 -08001537 clear_bit(FD_VERIFY_BIT, &DRS->flags);
1538 clear_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Joe Perches87f530d2010-03-10 15:20:54 -08001539 debug_dcl(DP->flags,
1540 "checking whether disk is write protected\n");
1541 debug_dcl(DP->flags, "wp=%x\n", ST3 & 0x40);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 if (!(ST3 & 0x40))
Joe Perchese0298532010-03-10 15:20:55 -08001543 set_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 else
Joe Perchese0298532010-03-10 15:20:55 -08001545 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 }
1547}
1548
1549static void seek_floppy(void)
1550{
1551 int track;
1552
1553 blind_seek = 0;
1554
Joe Perchesded28632010-03-10 15:21:09 -08001555 debug_dcl(DP->flags, "calling disk change from %s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556
Joe Perchese0298532010-03-10 15:20:55 -08001557 if (!test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1559 /* the media changed flag should be cleared after the seek.
1560 * If it isn't, this means that there is really no disk in
1561 * the drive.
1562 */
Joe Perchese0298532010-03-10 15:20:55 -08001563 set_bit(FD_DISK_CHANGED_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 cont->done(0);
1565 cont->redo();
1566 return;
1567 }
1568 if (DRS->track <= NEED_1_RECAL) {
1569 recalibrate_floppy();
1570 return;
Joe Perchese0298532010-03-10 15:20:55 -08001571 } else if (test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1573 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1574 /* we seek to clear the media-changed condition. Does anybody
1575 * know a more elegant way, which works on all drives? */
1576 if (raw_cmd->track)
1577 track = raw_cmd->track - 1;
1578 else {
1579 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1580 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1581 blind_seek = 1;
1582 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1583 }
1584 track = 1;
1585 }
1586 } else {
1587 check_wp();
1588 if (raw_cmd->track != DRS->track &&
1589 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1590 track = raw_cmd->track;
1591 else {
1592 setup_rw_floppy();
1593 return;
1594 }
1595 }
1596
1597 do_floppy = seek_interrupt;
1598 output_byte(FD_SEEK);
1599 output_byte(UNIT(current_drive));
Joe Perches2300f902010-03-10 15:20:49 -08001600 if (output_byte(track) < 0) {
1601 reset_fdc();
1602 return;
1603 }
Joe Perchesded28632010-03-10 15:21:09 -08001604 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605}
1606
1607static void recal_interrupt(void)
1608{
Joe Perchesded28632010-03-10 15:21:09 -08001609 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 if (inr != 2)
1611 FDCS->reset = 1;
1612 else if (ST0 & ST0_ECE) {
1613 switch (DRS->track) {
1614 case NEED_1_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001615 debugt(__func__, "need 1 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 /* after a second recalibrate, we still haven't
1617 * reached track 0. Probably no drive. Raise an
1618 * error, as failing immediately might upset
1619 * computers possessed by the Devil :-) */
1620 cont->error();
1621 cont->redo();
1622 return;
1623 case NEED_2_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001624 debugt(__func__, "need 2 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 /* If we already did a recalibrate,
1626 * and we are not at track 0, this
1627 * means we have moved. (The only way
1628 * not to move at recalibration is to
1629 * be already at track 0.) Clear the
1630 * new change flag */
Joe Perches87f530d2010-03-10 15:20:54 -08001631 debug_dcl(DP->flags,
1632 "clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633
Joe Perchese0298532010-03-10 15:20:55 -08001634 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 DRS->select_date = jiffies;
1636 /* fall through */
1637 default:
Joe Perchesded28632010-03-10 15:21:09 -08001638 debugt(__func__, "default");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 /* Recalibrate moves the head by at
1640 * most 80 steps. If after one
1641 * recalibrate we don't have reached
1642 * track 0, this might mean that we
1643 * started beyond track 80. Try
1644 * again. */
1645 DRS->track = NEED_1_RECAL;
1646 break;
1647 }
1648 } else
1649 DRS->track = ST1;
1650 floppy_ready();
1651}
1652
1653static void print_result(char *message, int inr)
1654{
1655 int i;
1656
1657 DPRINT("%s ", message);
1658 if (inr >= 0)
1659 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001660 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1661 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662}
1663
1664/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001665irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 int do_print;
1668 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001669 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670
1671 lasthandler = handler;
1672 interruptjiffies = jiffies;
1673
1674 f = claim_dma_lock();
1675 fd_disable_dma();
1676 release_dma_lock(f);
1677
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 do_floppy = NULL;
1679 if (fdc >= N_FDC || FDCS->address == -1) {
1680 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001681 pr_info("DOR0=%x\n", fdc_state[0].dor);
1682 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
Joe Perches1ebddd82010-03-10 15:21:07 -08001683 pr_info("handler=%pf\n", handler);
Joe Perches275176b2010-03-10 15:21:06 -08001684 is_alive(__func__, "bizarre fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 return IRQ_NONE;
1686 }
1687
1688 FDCS->reset = 0;
1689 /* We have to clear the reset flag here, because apparently on boxes
1690 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1691 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1692 * emission of the SENSEI's.
1693 * It is OK to emit floppy commands because we are in an interrupt
1694 * handler here, and thus we have to fear no interference of other
1695 * activity.
1696 */
1697
Joe Perches29f1c782010-03-10 15:21:00 -08001698 do_print = !handler && print_unex && initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699
1700 inr = result();
1701 if (do_print)
1702 print_result("unexpected interrupt", inr);
1703 if (inr == 0) {
1704 int max_sensei = 4;
1705 do {
1706 output_byte(FD_SENSEI);
1707 inr = result();
1708 if (do_print)
1709 print_result("sensei", inr);
1710 max_sensei--;
Joe Perchesc5297302010-03-10 15:20:58 -08001711 } while ((ST0 & 0x83) != UNIT(current_drive) &&
1712 inr == 2 && max_sensei);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 }
1714 if (!handler) {
1715 FDCS->reset = 1;
1716 return IRQ_NONE;
1717 }
1718 schedule_bh(handler);
Joe Perches275176b2010-03-10 15:21:06 -08001719 is_alive(__func__, "normal interrupt end");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720
1721 /* FIXME! Was it really for us? */
1722 return IRQ_HANDLED;
1723}
1724
1725static void recalibrate_floppy(void)
1726{
Joe Perchesded28632010-03-10 15:21:09 -08001727 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 do_floppy = recal_interrupt;
1729 output_byte(FD_RECALIBRATE);
Joe Perches15b26302010-03-10 15:21:01 -08001730 if (output_byte(UNIT(current_drive)) < 0)
Joe Perches2300f902010-03-10 15:20:49 -08001731 reset_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732}
1733
1734/*
1735 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1736 */
1737static void reset_interrupt(void)
1738{
Joe Perchesded28632010-03-10 15:21:09 -08001739 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 result(); /* get the status ready for set_fdc */
1741 if (FDCS->reset) {
Joe Perches1ebddd82010-03-10 15:21:07 -08001742 pr_info("reset set in interrupt, calling %pf\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 cont->error(); /* a reset just after a reset. BAD! */
1744 }
1745 cont->redo();
1746}
1747
1748/*
1749 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1750 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1751 */
1752static void reset_fdc(void)
1753{
1754 unsigned long flags;
1755
1756 do_floppy = reset_interrupt;
1757 FDCS->reset = 0;
1758 reset_fdc_info(0);
1759
1760 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1761 /* Irrelevant for systems with true DMA (i386). */
1762
1763 flags = claim_dma_lock();
1764 fd_disable_dma();
1765 release_dma_lock(flags);
1766
1767 if (FDCS->version >= FDC_82072A)
1768 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1769 else {
1770 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1771 udelay(FD_RESET_DELAY);
1772 fd_outb(FDCS->dor, FD_DOR);
1773 }
1774}
1775
1776static void show_floppy(void)
1777{
1778 int i;
1779
Joe Perchesb46df352010-03-10 15:20:46 -08001780 pr_info("\n");
1781 pr_info("floppy driver state\n");
1782 pr_info("-------------------\n");
Joe Perches1ebddd82010-03-10 15:21:07 -08001783 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%pf\n",
Joe Perchesb46df352010-03-10 15:20:46 -08001784 jiffies, interruptjiffies, jiffies - interruptjiffies,
1785 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786
Joe Perchesb46df352010-03-10 15:20:46 -08001787 pr_info("timeout_message=%s\n", timeout_message);
1788 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001790 pr_info("%2x %2x %lu\n",
1791 output_log[(i + output_log_pos) % OLOGSIZE].data,
1792 output_log[(i + output_log_pos) % OLOGSIZE].status,
1793 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1794 pr_info("last result at %lu\n", resultjiffies);
1795 pr_info("last redo_fd_request at %lu\n", lastredo);
1796 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1797 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798
Joe Perchesb46df352010-03-10 15:20:46 -08001799 pr_info("status=%x\n", fd_inb(FD_STATUS));
1800 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 if (do_floppy)
Joe Perches1ebddd82010-03-10 15:21:07 -08001802 pr_info("do_floppy=%pf\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001803 if (work_pending(&floppy_work))
Joe Perches1ebddd82010-03-10 15:21:07 -08001804 pr_info("floppy_work.func=%pf\n", floppy_work.func);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 if (timer_pending(&fd_timer))
Joe Perches1ebddd82010-03-10 15:21:07 -08001806 pr_info("fd_timer.function=%pf\n", fd_timer.function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 if (timer_pending(&fd_timeout)) {
Joe Perches1ebddd82010-03-10 15:21:07 -08001808 pr_info("timer_function=%pf\n", fd_timeout.function);
Joe Perchesb46df352010-03-10 15:20:46 -08001809 pr_info("expires=%lu\n", fd_timeout.expires - jiffies);
1810 pr_info("now=%lu\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 }
Joe Perchesb46df352010-03-10 15:20:46 -08001812 pr_info("cont=%p\n", cont);
1813 pr_info("current_req=%p\n", current_req);
1814 pr_info("command_status=%d\n", command_status);
1815 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816}
1817
1818static void floppy_shutdown(unsigned long data)
1819{
1820 unsigned long flags;
1821
Joe Perches29f1c782010-03-10 15:21:00 -08001822 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 show_floppy();
1824 cancel_activity();
1825
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 flags = claim_dma_lock();
1827 fd_disable_dma();
1828 release_dma_lock(flags);
1829
1830 /* avoid dma going to a random drive after shutdown */
1831
Joe Perches29f1c782010-03-10 15:21:00 -08001832 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 DPRINT("floppy timeout called\n");
1834 FDCS->reset = 1;
1835 if (cont) {
1836 cont->done(0);
1837 cont->redo(); /* this will recall reset when needed */
1838 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001839 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 process_fd_request();
1841 }
Joe Perches275176b2010-03-10 15:21:06 -08001842 is_alive(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843}
1844
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001846static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001848 int mask;
1849 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850
1851 mask = 0xfc;
1852 data = UNIT(current_drive);
1853 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1854 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1855 set_debugt();
1856 /* no read since this drive is running */
1857 DRS->first_read_date = 0;
1858 /* note motor start time if motor is not yet running */
1859 DRS->spinup_date = jiffies;
1860 data |= (0x10 << UNIT(current_drive));
1861 }
1862 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1863 mask &= ~(0x10 << UNIT(current_drive));
1864
1865 /* starts motor and selects floppy */
1866 del_timer(motor_off_timer + current_drive);
1867 set_dor(fdc, mask, data);
1868
1869 /* wait_for_completion also schedules reset if needed. */
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001870 return fd_wait_for_completion(DRS->select_date + DP->select_delay,
1871 (timeout_fn)function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872}
1873
1874static void floppy_ready(void)
1875{
Joe Perches045f9832010-03-10 15:20:47 -08001876 if (FDCS->reset) {
1877 reset_fdc();
1878 return;
1879 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 if (start_motor(floppy_ready))
1881 return;
1882 if (fdc_dtr())
1883 return;
1884
Joe Perches87f530d2010-03-10 15:20:54 -08001885 debug_dcl(DP->flags, "calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1887 disk_change(current_drive) && !DP->select_delay)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001888 twaddle(); /* this clears the dcl on certain
1889 * drive/controller combinations */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890
1891#ifdef fd_chose_dma_mode
1892 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1893 unsigned long flags = claim_dma_lock();
1894 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1895 release_dma_lock(flags);
1896 }
1897#endif
1898
1899 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1900 perpendicular_mode();
1901 fdc_specify(); /* must be done here because of hut, hlt ... */
1902 seek_floppy();
1903 } else {
1904 if ((raw_cmd->flags & FD_RAW_READ) ||
1905 (raw_cmd->flags & FD_RAW_WRITE))
1906 fdc_specify();
1907 setup_rw_floppy();
1908 }
1909}
1910
1911static void floppy_start(void)
1912{
Joe Perches73507e62010-03-10 15:21:03 -08001913 reschedule_timeout(current_reqD, "floppy start");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914
1915 scandrives();
Joe Perches87f530d2010-03-10 15:20:54 -08001916 debug_dcl(DP->flags, "setting NEWCHANGE in floppy_start\n");
Joe Perchese0298532010-03-10 15:20:55 -08001917 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 floppy_ready();
1919}
1920
1921/*
1922 * ========================================================================
1923 * here ends the bottom half. Exported routines are:
1924 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
1925 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
1926 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
1927 * and set_dor.
1928 * ========================================================================
1929 */
1930/*
1931 * General purpose continuations.
1932 * ==============================
1933 */
1934
1935static void do_wakeup(void)
1936{
Joe Perches73507e62010-03-10 15:21:03 -08001937 reschedule_timeout(MAXTIMEOUT, "do wakeup");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 cont = NULL;
1939 command_status += 2;
1940 wake_up(&command_done);
1941}
1942
Stephen Hemminger3b06c212010-07-20 20:09:00 -06001943static const struct cont_t wakeup_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 .interrupt = empty,
1945 .redo = do_wakeup,
1946 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07001947 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948};
1949
Stephen Hemminger3b06c212010-07-20 20:09:00 -06001950static const struct cont_t intr_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 .interrupt = empty,
1952 .redo = process_fd_request,
1953 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07001954 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955};
1956
Joe Perches74f63f42010-03-10 15:20:58 -08001957static int wait_til_done(void (*handler)(void), bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958{
1959 int ret;
1960
1961 schedule_bh(handler);
1962
Stephen Hemmingerb862f262010-06-15 13:21:11 +02001963 if (interruptible)
1964 wait_event_interruptible(command_done, command_status >= 2);
1965 else
1966 wait_event(command_done, command_status >= 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967
1968 if (command_status < 2) {
1969 cancel_activity();
1970 cont = &intr_cont;
1971 reset_fdc();
1972 return -EINTR;
1973 }
1974
1975 if (FDCS->reset)
1976 command_status = FD_COMMAND_ERROR;
1977 if (command_status == FD_COMMAND_OKAY)
1978 ret = 0;
1979 else
1980 ret = -EIO;
1981 command_status = FD_COMMAND_NONE;
1982 return ret;
1983}
1984
1985static void generic_done(int result)
1986{
1987 command_status = result;
1988 cont = &wakeup_cont;
1989}
1990
1991static void generic_success(void)
1992{
1993 cont->done(1);
1994}
1995
1996static void generic_failure(void)
1997{
1998 cont->done(0);
1999}
2000
2001static void success_and_wakeup(void)
2002{
2003 generic_success();
2004 cont->redo();
2005}
2006
2007/*
2008 * formatting and rw support.
2009 * ==========================
2010 */
2011
2012static int next_valid_format(void)
2013{
2014 int probed_format;
2015
2016 probed_format = DRS->probed_format;
2017 while (1) {
2018 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2019 DRS->probed_format = 0;
2020 return 1;
2021 }
2022 if (floppy_type[DP->autodetect[probed_format]].sect) {
2023 DRS->probed_format = probed_format;
2024 return 0;
2025 }
2026 probed_format++;
2027 }
2028}
2029
2030static void bad_flp_intr(void)
2031{
2032 int err_count;
2033
2034 if (probing) {
2035 DRS->probed_format++;
2036 if (!next_valid_format())
2037 return;
2038 }
2039 err_count = ++(*errors);
2040 INFBOUND(DRWE->badness, err_count);
2041 if (err_count > DP->max_errors.abort)
2042 cont->done(0);
2043 if (err_count > DP->max_errors.reset)
2044 FDCS->reset = 1;
2045 else if (err_count > DP->max_errors.recal)
2046 DRS->track = NEED_2_RECAL;
2047}
2048
2049static void set_floppy(int drive)
2050{
2051 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002052
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 if (type)
2054 _floppy = floppy_type + type;
2055 else
2056 _floppy = current_type[drive];
2057}
2058
2059/*
2060 * formatting support.
2061 * ===================
2062 */
2063static void format_interrupt(void)
2064{
2065 switch (interpret_errors()) {
2066 case 1:
2067 cont->error();
2068 case 2:
2069 break;
2070 case 0:
2071 cont->done(1);
2072 }
2073 cont->redo();
2074}
2075
Joe Perches48c8cee2010-03-10 15:20:45 -08002076#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002078
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079static void setup_format_params(int track)
2080{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002081 int n;
2082 int il;
2083 int count;
2084 int head_shift;
2085 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 struct fparm {
2087 unsigned char track, head, sect, size;
2088 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089
2090 raw_cmd = &default_raw_cmd;
2091 raw_cmd->track = track;
2092
Joe Perches48c8cee2010-03-10 15:20:45 -08002093 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2094 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 raw_cmd->rate = _floppy->rate & 0x43;
2096 raw_cmd->cmd_count = NR_F;
2097 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2098 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2099 F_SIZECODE = FD_SIZECODE(_floppy);
2100 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2101 F_GAP = _floppy->fmt_gap;
2102 F_FILL = FD_FILL_BYTE;
2103
2104 raw_cmd->kernel_data = floppy_track_buffer;
2105 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2106
2107 /* allow for about 30ms for data transport per track */
2108 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2109
2110 /* a ``cylinder'' is two tracks plus a little stepping time */
2111 track_shift = 2 * head_shift + 3;
2112
2113 /* position of logical sector 1 on this track */
2114 n = (track_shift * format_req.track + head_shift * format_req.head)
2115 % F_SECT_PER_TRACK;
2116
2117 /* determine interleave */
2118 il = 1;
2119 if (_floppy->fmt_gap < 0x22)
2120 il++;
2121
2122 /* initialize field */
2123 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2124 here[count].track = format_req.track;
2125 here[count].head = format_req.head;
2126 here[count].sect = 0;
2127 here[count].size = F_SIZECODE;
2128 }
2129 /* place logical sectors */
2130 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2131 here[n].sect = count;
2132 n = (n + il) % F_SECT_PER_TRACK;
2133 if (here[n].sect) { /* sector busy, find next free sector */
2134 ++n;
2135 if (n >= F_SECT_PER_TRACK) {
2136 n -= F_SECT_PER_TRACK;
2137 while (here[n].sect)
2138 ++n;
2139 }
2140 }
2141 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002142 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002144 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 }
2146}
2147
2148static void redo_format(void)
2149{
2150 buffer_track = -1;
2151 setup_format_params(format_req.track << STRETCH(_floppy));
2152 floppy_start();
Joe Perchesded28632010-03-10 15:21:09 -08002153 debugt(__func__, "queue format request");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154}
2155
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002156static const struct cont_t format_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 .interrupt = format_interrupt,
2158 .redo = redo_format,
2159 .error = bad_flp_intr,
2160 .done = generic_done
2161};
2162
2163static int do_format(int drive, struct format_descr *tmp_format_req)
2164{
2165 int ret;
2166
Joe Perches74f63f42010-03-10 15:20:58 -08002167 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08002168 return -EINTR;
2169
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 set_floppy(drive);
2171 if (!_floppy ||
2172 _floppy->track > DP->tracks ||
2173 tmp_format_req->track >= _floppy->track ||
2174 tmp_format_req->head >= _floppy->head ||
2175 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2176 !_floppy->fmt_gap) {
2177 process_fd_request();
2178 return -EINVAL;
2179 }
2180 format_req = *tmp_format_req;
2181 format_errors = 0;
2182 cont = &format_cont;
2183 errors = &format_errors;
Joe Perches74f63f42010-03-10 15:20:58 -08002184 ret = wait_til_done(redo_format, true);
Joe Perches55eee802010-03-10 15:20:57 -08002185 if (ret == -EINTR)
2186 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 process_fd_request();
2188 return ret;
2189}
2190
2191/*
2192 * Buffer read/write and support
2193 * =============================
2194 */
2195
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002196static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197{
2198 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002199 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200
2201 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002202 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002203 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002204 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206
2207 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002208 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 current_req = NULL;
2210}
2211
2212/* new request_done. Can handle physical sectors which are smaller than a
2213 * logical buffer */
2214static void request_done(int uptodate)
2215{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 struct request *req = current_req;
Jens Axboe48821182010-09-22 09:32:36 +02002217 struct request_queue *q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 unsigned long flags;
2219 int block;
Joe Perches73507e62010-03-10 15:21:03 -08002220 char msg[sizeof("request done ") + sizeof(int) * 3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221
2222 probing = 0;
Joe Perches73507e62010-03-10 15:21:03 -08002223 snprintf(msg, sizeof(msg), "request done %d", uptodate);
2224 reschedule_timeout(MAXTIMEOUT, msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225
2226 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002227 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 return;
2229 }
2230
Jens Axboe48821182010-09-22 09:32:36 +02002231 q = req->q;
2232
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 if (uptodate) {
2234 /* maintain values for invalidation on geometry
2235 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002236 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 INFBOUND(DRS->maxblock, block);
2238 if (block > _floppy->sect)
2239 DRS->maxtrack = 1;
2240
2241 /* unlock chained buffers */
2242 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002243 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244 spin_unlock_irqrestore(q->queue_lock, flags);
2245 } else {
2246 if (rq_data_dir(req) == WRITE) {
2247 /* record write error information */
2248 DRWE->write_errors++;
2249 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002250 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 DRWE->first_error_generation = DRS->generation;
2252 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002253 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 DRWE->last_error_generation = DRS->generation;
2255 }
2256 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002257 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 spin_unlock_irqrestore(q->queue_lock, flags);
2259 }
2260}
2261
2262/* Interrupt handler evaluating the result of the r/w operation */
2263static void rw_interrupt(void)
2264{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002265 int eoc;
2266 int ssize;
2267 int heads;
2268 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269
2270 if (R_HEAD >= 2) {
2271 /* some Toshiba floppy controllers occasionnally seem to
2272 * return bogus interrupts after read/write operations, which
2273 * can be recognized by a bad head number (>= 2) */
2274 return;
2275 }
2276
2277 if (!DRS->first_read_date)
2278 DRS->first_read_date = jiffies;
2279
2280 nr_sectors = 0;
Joe Perches712e1de2010-03-10 15:21:10 -08002281 ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282
2283 if (ST1 & ST1_EOC)
2284 eoc = 1;
2285 else
2286 eoc = 0;
2287
2288 if (COMMAND & 0x80)
2289 heads = 2;
2290 else
2291 heads = 1;
2292
2293 nr_sectors = (((R_TRACK - TRACK) * heads +
2294 R_HEAD - HEAD) * SECT_PER_TRACK +
2295 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2296
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002298 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299 DPRINT("long rw: %x instead of %lx\n",
2300 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002301 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2302 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2303 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2304 pr_info("heads=%d eoc=%d\n", heads, eoc);
2305 pr_info("spt=%d st=%d ss=%d\n",
2306 SECT_PER_TRACK, fsector_t, ssize);
2307 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309
2310 nr_sectors -= in_sector_offset;
2311 INFBOUND(nr_sectors, 0);
2312 SUPBOUND(current_count_sectors, nr_sectors);
2313
2314 switch (interpret_errors()) {
2315 case 2:
2316 cont->redo();
2317 return;
2318 case 1:
2319 if (!current_count_sectors) {
2320 cont->error();
2321 cont->redo();
2322 return;
2323 }
2324 break;
2325 case 0:
2326 if (!current_count_sectors) {
2327 cont->redo();
2328 return;
2329 }
2330 current_type[current_drive] = _floppy;
2331 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2332 break;
2333 }
2334
2335 if (probing) {
2336 if (DP->flags & FTD_MSG)
2337 DPRINT("Auto-detected floppy type %s in fd%d\n",
2338 _floppy->name, current_drive);
2339 current_type[current_drive] = _floppy;
2340 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2341 probing = 0;
2342 }
2343
2344 if (CT(COMMAND) != FD_READ ||
2345 raw_cmd->kernel_data == current_req->buffer) {
2346 /* transfer directly from buffer */
2347 cont->done(1);
2348 } else if (CT(COMMAND) == FD_READ) {
2349 buffer_track = raw_cmd->track;
2350 buffer_drive = current_drive;
2351 INFBOUND(buffer_max, nr_sectors + fsector_t);
2352 }
2353 cont->redo();
2354}
2355
2356/* Compute maximal contiguous buffer size. */
2357static int buffer_chain_size(void)
2358{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 struct bio_vec *bv;
NeilBrown5705f702007-09-25 12:35:59 +02002360 int size;
2361 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 char *base;
2363
2364 base = bio_data(current_req->bio);
2365 size = 0;
2366
NeilBrown5705f702007-09-25 12:35:59 +02002367 rq_for_each_segment(bv, current_req, iter) {
2368 if (page_address(bv->bv_page) + bv->bv_offset != base + size)
2369 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370
NeilBrown5705f702007-09-25 12:35:59 +02002371 size += bv->bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 }
2373
2374 return size >> 9;
2375}
2376
2377/* Compute the maximal transfer size */
2378static int transfer_size(int ssize, int max_sector, int max_size)
2379{
2380 SUPBOUND(max_sector, fsector_t + max_size);
2381
2382 /* alignment */
2383 max_sector -= (max_sector % _floppy->sect) % ssize;
2384
2385 /* transfer size, beginning not aligned */
2386 current_count_sectors = max_sector - fsector_t;
2387
2388 return max_sector;
2389}
2390
2391/*
2392 * Move data from/to the track buffer to/from the buffer cache.
2393 */
2394static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2395{
2396 int remaining; /* number of transferred 512-byte sectors */
2397 struct bio_vec *bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002398 char *buffer;
2399 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002400 int size;
2401 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402
2403 max_sector = transfer_size(ssize,
2404 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002405 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406
2407 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002408 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002410 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411
2412 remaining = current_count_sectors << 9;
Tejun Heo1011c1b2009-05-07 22:24:45 +09002413 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002415 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2416 pr_info("remaining=%d\n", remaining >> 9);
2417 pr_info("current_req->nr_sectors=%u\n",
2418 blk_rq_sectors(current_req));
2419 pr_info("current_req->current_nr_sectors=%u\n",
2420 blk_rq_cur_sectors(current_req));
2421 pr_info("max_sector=%d\n", max_sector);
2422 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424
2425 buffer_max = max(max_sector, buffer_max);
2426
2427 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2428
Tejun Heo1011c1b2009-05-07 22:24:45 +09002429 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430
NeilBrown5705f702007-09-25 12:35:59 +02002431 rq_for_each_segment(bv, current_req, iter) {
2432 if (!remaining)
2433 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434
NeilBrown5705f702007-09-25 12:35:59 +02002435 size = bv->bv_len;
2436 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437
NeilBrown5705f702007-09-25 12:35:59 +02002438 buffer = page_address(bv->bv_page) + bv->bv_offset;
NeilBrown5705f702007-09-25 12:35:59 +02002439 if (dma_buffer + size >
2440 floppy_track_buffer + (max_buffer_sectors << 10) ||
2441 dma_buffer < floppy_track_buffer) {
2442 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002443 (int)((floppy_track_buffer - dma_buffer) >> 9));
2444 pr_info("fsector_t=%d buffer_min=%d\n",
2445 fsector_t, buffer_min);
2446 pr_info("current_count_sectors=%ld\n",
2447 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002449 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002450 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002451 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002452 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 }
NeilBrown5705f702007-09-25 12:35:59 +02002454 if (((unsigned long)buffer) % 512)
2455 DPRINT("%p buffer not aligned\n", buffer);
Joe Perches1a23d132010-03-10 15:21:04 -08002456
NeilBrown5705f702007-09-25 12:35:59 +02002457 if (CT(COMMAND) == FD_READ)
2458 memcpy(buffer, dma_buffer, size);
2459 else
2460 memcpy(dma_buffer, buffer, size);
2461
2462 remaining -= size;
2463 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 if (remaining) {
2466 if (remaining > 0)
2467 max_sector -= remaining >> 9;
2468 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2469 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470}
2471
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472/* work around a bug in pseudo DMA
2473 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2474 * sending data. Hence we need a different way to signal the
2475 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2476 * does not work with MT, hence we can only transfer one head at
2477 * a time
2478 */
2479static void virtualdmabug_workaround(void)
2480{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002481 int hard_sectors;
2482 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483
2484 if (CT(COMMAND) == FD_WRITE) {
2485 COMMAND &= ~0x80; /* switch off multiple track mode */
2486
2487 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2488 end_sector = SECTOR + hard_sectors - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002490 pr_info("too many sectors %d > %d\n",
2491 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 return;
2493 }
Joe Perches48c8cee2010-03-10 15:20:45 -08002494 SECT_PER_TRACK = end_sector;
2495 /* make sure SECT_PER_TRACK
2496 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 }
2498}
2499
2500/*
2501 * Formulate a read/write request.
2502 * this routine decides where to load the data (directly to buffer, or to
2503 * tmp floppy area), how much data to load (the size of the buffer, the whole
2504 * track, or a single sector)
2505 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2506 * allocation on the fly, it should be done here. No other part should need
2507 * modification.
2508 */
2509
2510static int make_raw_rw_request(void)
2511{
2512 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002513 int max_sector;
2514 int max_size;
2515 int tracksize;
2516 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002518 if (WARN(max_buffer_sectors == 0, "VFS: Block I/O scheduled on unopened device\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520
2521 set_fdc((long)current_req->rq_disk->private_data);
2522
2523 raw_cmd = &default_raw_cmd;
2524 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
2525 FD_RAW_NEED_SEEK;
2526 raw_cmd->cmd_count = NR_RW;
2527 if (rq_data_dir(current_req) == READ) {
2528 raw_cmd->flags |= FD_RAW_READ;
2529 COMMAND = FM_MODE(_floppy, FD_READ);
2530 } else if (rq_data_dir(current_req) == WRITE) {
2531 raw_cmd->flags |= FD_RAW_WRITE;
2532 COMMAND = FM_MODE(_floppy, FD_WRITE);
2533 } else {
Joe Perches275176b2010-03-10 15:21:06 -08002534 DPRINT("%s: unknown command\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 return 0;
2536 }
2537
2538 max_sector = _floppy->sect * _floppy->head;
2539
Tejun Heo83096eb2009-05-07 22:24:39 +09002540 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2541 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002543 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 current_count_sectors = 1;
2545 return 1;
2546 } else
2547 return 0;
2548 }
2549 HEAD = fsector_t / _floppy->sect;
2550
Keith Wansbrough9e491842008-09-22 14:57:17 -07002551 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Joe Perchese0298532010-03-10 15:20:55 -08002552 test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags)) &&
2553 fsector_t < _floppy->sect)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 max_sector = _floppy->sect;
2555
2556 /* 2M disks have phantom sectors on the first track */
2557 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2558 max_sector = 2 * _floppy->sect / 3;
2559 if (fsector_t >= max_sector) {
2560 current_count_sectors =
2561 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002562 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 return 1;
2564 }
2565 SIZECODE = 2;
2566 } else
2567 SIZECODE = FD_SIZECODE(_floppy);
2568 raw_cmd->rate = _floppy->rate & 0x43;
2569 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2570 raw_cmd->rate = 1;
2571
2572 if (SIZECODE)
2573 SIZECODE2 = 0xff;
2574 else
2575 SIZECODE2 = 0x80;
2576 raw_cmd->track = TRACK << STRETCH(_floppy);
2577 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2578 GAP = _floppy->gap;
Joe Perches712e1de2010-03-10 15:21:10 -08002579 ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2581 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002582 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583
2584 /* tracksize describes the size which can be filled up with sectors
2585 * of size ssize.
2586 */
2587 tracksize = _floppy->sect - _floppy->sect % ssize;
2588 if (tracksize < _floppy->sect) {
2589 SECT_PER_TRACK++;
2590 if (tracksize <= fsector_t % _floppy->sect)
2591 SECTOR--;
2592
2593 /* if we are beyond tracksize, fill up using smaller sectors */
2594 while (tracksize <= fsector_t % _floppy->sect) {
2595 while (tracksize + ssize > _floppy->sect) {
2596 SIZECODE--;
2597 ssize >>= 1;
2598 }
2599 SECTOR++;
2600 SECT_PER_TRACK++;
2601 tracksize += ssize;
2602 }
2603 max_sector = HEAD * _floppy->sect + tracksize;
2604 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2605 max_sector = _floppy->sect;
2606 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2607 /* for virtual DMA bug workaround */
2608 max_sector = _floppy->sect;
2609 }
2610
2611 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2612 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002613 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 if ((raw_cmd->track == buffer_track) &&
2615 (current_drive == buffer_drive) &&
2616 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2617 /* data already in track buffer */
2618 if (CT(COMMAND) == FD_READ) {
2619 copy_buffer(1, max_sector, buffer_max);
2620 return 1;
2621 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002622 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 if (CT(COMMAND) == FD_WRITE) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002624 unsigned int sectors;
2625
2626 sectors = fsector_t + blk_rq_sectors(current_req);
2627 if (sectors > ssize && sectors < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 max_size = ssize + ssize;
2629 else
2630 max_size = ssize;
2631 }
2632 raw_cmd->flags &= ~FD_RAW_WRITE;
2633 raw_cmd->flags |= FD_RAW_READ;
2634 COMMAND = FM_MODE(_floppy, FD_READ);
2635 } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) {
2636 unsigned long dma_limit;
2637 int direct, indirect;
2638
2639 indirect =
2640 transfer_size(ssize, max_sector,
2641 max_buffer_sectors * 2) - fsector_t;
2642
2643 /*
2644 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2645 * on a 64 bit machine!
2646 */
2647 max_size = buffer_chain_size();
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002648 dma_limit = (MAX_DMA_ADDRESS -
2649 ((unsigned long)current_req->buffer)) >> 9;
Joe Perchesa81ee542010-03-10 15:20:46 -08002650 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 /* 64 kb boundaries */
2653 if (CROSS_64KB(current_req->buffer, max_size << 9))
2654 max_size = (K_64 -
2655 ((unsigned long)current_req->buffer) %
2656 K_64) >> 9;
2657 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2658 /*
2659 * We try to read tracks, but if we get too many errors, we
2660 * go back to reading just one sector at a time.
2661 *
2662 * This means we should be able to read a sector even if there
2663 * are other bad sectors on this track.
2664 */
2665 if (!direct ||
2666 (indirect * 2 > direct * 3 &&
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002667 *errors < DP->max_errors.read_track &&
2668 ((!probing ||
2669 (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002670 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 } else {
2672 raw_cmd->kernel_data = current_req->buffer;
2673 raw_cmd->length = current_count_sectors << 9;
2674 if (raw_cmd->length == 0) {
Joe Perches275176b2010-03-10 15:21:06 -08002675 DPRINT("%s: zero dma transfer attempted\n", __func__);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002676 DPRINT("indirect=%d direct=%d fsector_t=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 indirect, direct, fsector_t);
2678 return 0;
2679 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 virtualdmabug_workaround();
2681 return 2;
2682 }
2683 }
2684
2685 if (CT(COMMAND) == FD_READ)
2686 max_size = max_sector; /* unbounded */
2687
2688 /* claim buffer track if needed */
2689 if (buffer_track != raw_cmd->track || /* bad track */
2690 buffer_drive != current_drive || /* bad drive */
2691 fsector_t > buffer_max ||
2692 fsector_t < buffer_min ||
2693 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002694 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 max_sector > 2 * max_buffer_sectors + buffer_min &&
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002696 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
2697 /* not enough space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 buffer_track = -1;
2699 buffer_drive = current_drive;
2700 buffer_max = buffer_min = aligned_sector_t;
2701 }
2702 raw_cmd->kernel_data = floppy_track_buffer +
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002703 ((aligned_sector_t - buffer_min) << 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
2705 if (CT(COMMAND) == FD_WRITE) {
2706 /* copy write buffer to track buffer.
2707 * if we get here, we know that the write
2708 * is either aligned or the data already in the buffer
2709 * (buffer will be overwritten) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 if (in_sector_offset && buffer_track == -1)
2711 DPRINT("internal error offset !=0 on write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 buffer_track = raw_cmd->track;
2713 buffer_drive = current_drive;
2714 copy_buffer(ssize, max_sector,
2715 2 * max_buffer_sectors + buffer_min);
2716 } else
2717 transfer_size(ssize, max_sector,
2718 2 * max_buffer_sectors + buffer_min -
2719 aligned_sector_t);
2720
2721 /* round up current_count_sectors to get dma xfer size */
2722 raw_cmd->length = in_sector_offset + current_count_sectors;
2723 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2724 raw_cmd->length <<= 9;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 if ((raw_cmd->length < current_count_sectors << 9) ||
2726 (raw_cmd->kernel_data != current_req->buffer &&
2727 CT(COMMAND) == FD_WRITE &&
2728 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2729 aligned_sector_t < buffer_min)) ||
2730 raw_cmd->length % (128 << SIZECODE) ||
2731 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2732 DPRINT("fractionary current count b=%lx s=%lx\n",
2733 raw_cmd->length, current_count_sectors);
2734 if (raw_cmd->kernel_data != current_req->buffer)
Joe Perchesb46df352010-03-10 15:20:46 -08002735 pr_info("addr=%d, length=%ld\n",
2736 (int)((raw_cmd->kernel_data -
2737 floppy_track_buffer) >> 9),
2738 current_count_sectors);
2739 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2740 fsector_t, aligned_sector_t, max_sector, max_size);
2741 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2742 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2743 COMMAND, SECTOR, HEAD, TRACK);
2744 pr_info("buffer drive=%d\n", buffer_drive);
2745 pr_info("buffer track=%d\n", buffer_track);
2746 pr_info("buffer_min=%d\n", buffer_min);
2747 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 return 0;
2749 }
2750
2751 if (raw_cmd->kernel_data != current_req->buffer) {
2752 if (raw_cmd->kernel_data < floppy_track_buffer ||
2753 current_count_sectors < 0 ||
2754 raw_cmd->length < 0 ||
2755 raw_cmd->kernel_data + raw_cmd->length >
2756 floppy_track_buffer + (max_buffer_sectors << 10)) {
2757 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002758 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2759 fsector_t, buffer_min, raw_cmd->length >> 9);
2760 pr_info("current_count_sectors=%ld\n",
2761 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002763 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002765 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 return 0;
2767 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002768 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002769 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 DPRINT("buffer overrun in direct transfer\n");
2771 return 0;
2772 } else if (raw_cmd->length < current_count_sectors << 9) {
2773 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002774 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2775 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 }
2777 if (raw_cmd->length == 0) {
2778 DPRINT("zero dma transfer attempted from make_raw_request\n");
2779 return 0;
2780 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781
2782 virtualdmabug_workaround();
2783 return 2;
2784}
2785
Jens Axboe48821182010-09-22 09:32:36 +02002786/*
2787 * Round-robin between our available drives, doing one request from each
2788 */
2789static int set_next_request(void)
2790{
2791 struct request_queue *q;
2792 int old_pos = fdc_queue;
2793
2794 do {
2795 q = disks[fdc_queue]->queue;
2796 if (++fdc_queue == N_DRIVE)
2797 fdc_queue = 0;
2798 if (q) {
2799 current_req = blk_fetch_request(q);
2800 if (current_req)
2801 break;
2802 }
2803 } while (fdc_queue != old_pos);
2804
2805 return current_req != NULL;
2806}
2807
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808static void redo_fd_request(void)
2809{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 int drive;
2811 int tmp;
2812
2813 lastredo = jiffies;
2814 if (current_drive < N_DRIVE)
2815 floppy_off(current_drive);
2816
Joe Perches0da31322010-03-10 15:21:03 -08002817do_request:
2818 if (!current_req) {
Jens Axboe48821182010-09-22 09:32:36 +02002819 int pending;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820
Jens Axboe48821182010-09-22 09:32:36 +02002821 spin_lock_irq(&floppy_lock);
2822 pending = set_next_request();
2823 spin_unlock_irq(&floppy_lock);
2824
2825 if (!pending) {
Joe Perches0da31322010-03-10 15:21:03 -08002826 do_floppy = NULL;
2827 unlock_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 }
Joe Perches0da31322010-03-10 15:21:03 -08002831 drive = (long)current_req->rq_disk->private_data;
2832 set_fdc(drive);
Joe Perches73507e62010-03-10 15:21:03 -08002833 reschedule_timeout(current_reqD, "redo fd request");
Joe Perches0da31322010-03-10 15:21:03 -08002834
2835 set_floppy(drive);
2836 raw_cmd = &default_raw_cmd;
2837 raw_cmd->flags = 0;
2838 if (start_motor(redo_fd_request))
2839 return;
2840
2841 disk_change(current_drive);
2842 if (test_bit(current_drive, &fake_change) ||
2843 test_bit(FD_DISK_CHANGED_BIT, &DRS->flags)) {
2844 DPRINT("disk absent or changed during operation\n");
2845 request_done(0);
2846 goto do_request;
2847 }
2848 if (!_floppy) { /* Autodetection */
2849 if (!probing) {
2850 DRS->probed_format = 0;
2851 if (next_valid_format()) {
2852 DPRINT("no autodetectable formats\n");
2853 _floppy = NULL;
2854 request_done(0);
2855 goto do_request;
2856 }
2857 }
2858 probing = 1;
2859 _floppy = floppy_type + DP->autodetect[DRS->probed_format];
2860 } else
2861 probing = 0;
2862 errors = &(current_req->errors);
2863 tmp = make_raw_rw_request();
2864 if (tmp < 2) {
2865 request_done(tmp);
2866 goto do_request;
2867 }
2868
2869 if (test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags))
2870 twaddle();
2871 schedule_bh(floppy_start);
Joe Perchesded28632010-03-10 15:21:09 -08002872 debugt(__func__, "queue fd request");
Joe Perches0da31322010-03-10 15:21:03 -08002873 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874}
2875
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002876static const struct cont_t rw_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 .interrupt = rw_interrupt,
2878 .redo = redo_fd_request,
2879 .error = bad_flp_intr,
2880 .done = request_done
2881};
2882
2883static void process_fd_request(void)
2884{
2885 cont = &rw_cont;
2886 schedule_bh(redo_fd_request);
2887}
2888
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002889static void do_fd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890{
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002891 if (WARN(max_buffer_sectors == 0,
2892 "VFS: %s called on non-open device\n", __func__))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002895 if (WARN(atomic_read(&usage_count) == 0,
2896 "warning: usage count=0, current_req=%p sect=%ld type=%x flags=%x\n",
2897 current_req, (long)blk_rq_pos(current_req), current_req->cmd_type,
2898 current_req->cmd_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 return;
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002900
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 if (test_bit(0, &fdc_busy)) {
2902 /* fdc busy, this new request will be treated when the
2903 current one is done */
Joe Perches275176b2010-03-10 15:21:06 -08002904 is_alive(__func__, "old request running");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 return;
2906 }
Joe Perches74f63f42010-03-10 15:20:58 -08002907 lock_fdc(MAXTIMEOUT, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 process_fd_request();
Joe Perches275176b2010-03-10 15:21:06 -08002909 is_alive(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910}
2911
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002912static const struct cont_t poll_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 .interrupt = success_and_wakeup,
2914 .redo = floppy_ready,
2915 .error = generic_failure,
2916 .done = generic_done
2917};
2918
Joe Perches74f63f42010-03-10 15:20:58 -08002919static int poll_drive(bool interruptible, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 /* no auto-sense, just clear dcl */
2922 raw_cmd = &default_raw_cmd;
2923 raw_cmd->flags = flag;
2924 raw_cmd->track = 0;
2925 raw_cmd->cmd_count = 0;
2926 cont = &poll_cont;
Joe Perches87f530d2010-03-10 15:20:54 -08002927 debug_dcl(DP->flags, "setting NEWCHANGE in poll_drive\n");
Joe Perchese0298532010-03-10 15:20:55 -08002928 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Joe Perches55eee802010-03-10 15:20:57 -08002929
2930 return wait_til_done(floppy_ready, interruptible);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931}
2932
2933/*
2934 * User triggered reset
2935 * ====================
2936 */
2937
2938static void reset_intr(void)
2939{
Joe Perchesb46df352010-03-10 15:20:46 -08002940 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941}
2942
Stephen Hemminger3b06c212010-07-20 20:09:00 -06002943static const struct cont_t reset_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 .interrupt = reset_intr,
2945 .redo = success_and_wakeup,
2946 .error = generic_failure,
2947 .done = generic_done
2948};
2949
Joe Perches74f63f42010-03-10 15:20:58 -08002950static int user_reset_fdc(int drive, int arg, bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951{
2952 int ret;
2953
Joe Perches52a0d612010-03-10 15:20:53 -08002954 if (lock_fdc(drive, interruptible))
2955 return -EINTR;
2956
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 if (arg == FD_RESET_ALWAYS)
2958 FDCS->reset = 1;
2959 if (FDCS->reset) {
2960 cont = &reset_cont;
Joe Perches55eee802010-03-10 15:20:57 -08002961 ret = wait_til_done(reset_fdc, interruptible);
2962 if (ret == -EINTR)
2963 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 }
2965 process_fd_request();
Joe Perches52a0d612010-03-10 15:20:53 -08002966 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967}
2968
2969/*
2970 * Misc Ioctl's and support
2971 * ========================
2972 */
2973static inline int fd_copyout(void __user *param, const void *address,
2974 unsigned long size)
2975{
2976 return copy_to_user(param, address, size) ? -EFAULT : 0;
2977}
2978
Joe Perches48c8cee2010-03-10 15:20:45 -08002979static inline int fd_copyin(void __user *param, void *address,
2980 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981{
2982 return copy_from_user(address, param, size) ? -EFAULT : 0;
2983}
2984
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02002985static const char *drive_name(int type, int drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986{
2987 struct floppy_struct *floppy;
2988
2989 if (type)
2990 floppy = floppy_type + type;
2991 else {
2992 if (UDP->native_format)
2993 floppy = floppy_type + UDP->native_format;
2994 else
2995 return "(null)";
2996 }
2997 if (floppy->name)
2998 return floppy->name;
2999 else
3000 return "(null)";
3001}
3002
3003/* raw commands */
3004static void raw_cmd_done(int flag)
3005{
3006 int i;
3007
3008 if (!flag) {
3009 raw_cmd->flags |= FD_RAW_FAILURE;
3010 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3011 } else {
3012 raw_cmd->reply_count = inr;
3013 if (raw_cmd->reply_count > MAX_REPLIES)
3014 raw_cmd->reply_count = 0;
3015 for (i = 0; i < raw_cmd->reply_count; i++)
3016 raw_cmd->reply[i] = reply_buffer[i];
3017
3018 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3019 unsigned long flags;
3020 flags = claim_dma_lock();
3021 raw_cmd->length = fd_get_dma_residue();
3022 release_dma_lock(flags);
3023 }
3024
3025 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3026 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3027 raw_cmd->flags |= FD_RAW_FAILURE;
3028
3029 if (disk_change(current_drive))
3030 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3031 else
3032 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3033 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3034 motor_off_callback(current_drive);
3035
3036 if (raw_cmd->next &&
3037 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3038 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3039 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3040 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3041 raw_cmd = raw_cmd->next;
3042 return;
3043 }
3044 }
3045 generic_done(flag);
3046}
3047
Stephen Hemminger3b06c212010-07-20 20:09:00 -06003048static const struct cont_t raw_cmd_cont = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049 .interrupt = success_and_wakeup,
3050 .redo = floppy_start,
3051 .error = generic_failure,
3052 .done = raw_cmd_done
3053};
3054
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003055static int raw_cmd_copyout(int cmd, void __user *param,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 struct floppy_raw_cmd *ptr)
3057{
3058 int ret;
3059
3060 while (ptr) {
Joe Perchesce2f11f2010-03-10 15:21:08 -08003061 ret = copy_to_user(param, ptr, sizeof(*ptr));
Joe Perches86b12b42010-03-10 15:20:56 -08003062 if (ret)
3063 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 param += sizeof(struct floppy_raw_cmd);
3065 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003066 if (ptr->length >= 0 &&
3067 ptr->length <= ptr->buffer_length) {
3068 long length = ptr->buffer_length - ptr->length;
Joe Perches4575b552010-03-10 15:20:55 -08003069 ret = fd_copyout(ptr->data, ptr->kernel_data,
3070 length);
3071 if (ret)
3072 return ret;
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003073 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074 }
3075 ptr = ptr->next;
3076 }
Joe Perches7f252712010-03-10 15:21:08 -08003077
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 return 0;
3079}
3080
3081static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3082{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003083 struct floppy_raw_cmd *next;
3084 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085
3086 this = *ptr;
3087 *ptr = NULL;
3088 while (this) {
3089 if (this->buffer_length) {
3090 fd_dma_mem_free((unsigned long)this->kernel_data,
3091 this->buffer_length);
3092 this->buffer_length = 0;
3093 }
3094 next = this->next;
3095 kfree(this);
3096 this = next;
3097 }
3098}
3099
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003100static int raw_cmd_copyin(int cmd, void __user *param,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 struct floppy_raw_cmd **rcmd)
3102{
3103 struct floppy_raw_cmd *ptr;
3104 int ret;
3105 int i;
3106
3107 *rcmd = NULL;
Joe Perches7f252712010-03-10 15:21:08 -08003108
3109loop:
3110 ptr = kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3111 if (!ptr)
3112 return -ENOMEM;
3113 *rcmd = ptr;
3114 ret = copy_from_user(ptr, param, sizeof(*ptr));
3115 if (ret)
3116 return -EFAULT;
3117 ptr->next = NULL;
3118 ptr->buffer_length = 0;
3119 param += sizeof(struct floppy_raw_cmd);
3120 if (ptr->cmd_count > 33)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 /* the command may now also take up the space
3122 * initially intended for the reply & the
3123 * reply count. Needed for long 82078 commands
3124 * such as RESTORE, which takes ... 17 command
3125 * bytes. Murphy's law #137: When you reserve
3126 * 16 bytes for a structure, you'll one day
3127 * discover that you really need 17...
3128 */
Joe Perches7f252712010-03-10 15:21:08 -08003129 return -EINVAL;
3130
3131 for (i = 0; i < 16; i++)
3132 ptr->reply[i] = 0;
3133 ptr->resultcode = 0;
3134 ptr->kernel_data = NULL;
3135
3136 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3137 if (ptr->length <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138 return -EINVAL;
Joe Perches7f252712010-03-10 15:21:08 -08003139 ptr->kernel_data = (char *)fd_dma_mem_alloc(ptr->length);
3140 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3141 if (!ptr->kernel_data)
3142 return -ENOMEM;
3143 ptr->buffer_length = ptr->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 }
Joe Perches7f252712010-03-10 15:21:08 -08003145 if (ptr->flags & FD_RAW_WRITE) {
3146 ret = fd_copyin(ptr->data, ptr->kernel_data, ptr->length);
3147 if (ret)
3148 return ret;
3149 }
3150
3151 if (ptr->flags & FD_RAW_MORE) {
3152 rcmd = &(ptr->next);
3153 ptr->rate &= 0x43;
3154 goto loop;
3155 }
3156
3157 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158}
3159
3160static int raw_cmd_ioctl(int cmd, void __user *param)
3161{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003163 int drive;
3164 int ret2;
3165 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166
3167 if (FDCS->rawcmd <= 1)
3168 FDCS->rawcmd = 1;
3169 for (drive = 0; drive < N_DRIVE; drive++) {
3170 if (FDC(drive) != fdc)
3171 continue;
3172 if (drive == current_drive) {
3173 if (UDRS->fd_ref > 1) {
3174 FDCS->rawcmd = 2;
3175 break;
3176 }
3177 } else if (UDRS->fd_ref) {
3178 FDCS->rawcmd = 2;
3179 break;
3180 }
3181 }
3182
3183 if (FDCS->reset)
3184 return -EIO;
3185
3186 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3187 if (ret) {
3188 raw_cmd_free(&my_raw_cmd);
3189 return ret;
3190 }
3191
3192 raw_cmd = my_raw_cmd;
3193 cont = &raw_cmd_cont;
Joe Perches74f63f42010-03-10 15:20:58 -08003194 ret = wait_til_done(floppy_start, true);
Joe Perches87f530d2010-03-10 15:20:54 -08003195 debug_dcl(DP->flags, "calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196
3197 if (ret != -EINTR && FDCS->reset)
3198 ret = -EIO;
3199
3200 DRS->track = NO_TRACK;
3201
3202 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3203 if (!ret)
3204 ret = ret2;
3205 raw_cmd_free(&my_raw_cmd);
3206 return ret;
3207}
3208
3209static int invalidate_drive(struct block_device *bdev)
3210{
3211 /* invalidate the buffer track to force a reread */
3212 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3213 process_fd_request();
3214 check_disk_change(bdev);
3215 return 0;
3216}
3217
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003218static int set_geometry(unsigned int cmd, struct floppy_struct *g,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219 int drive, int type, struct block_device *bdev)
3220{
3221 int cnt;
3222
3223 /* sanity checking for parameters. */
3224 if (g->sect <= 0 ||
3225 g->head <= 0 ||
3226 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3227 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003228 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229 return -EINVAL;
3230 if (type) {
3231 if (!capable(CAP_SYS_ADMIN))
3232 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003233 mutex_lock(&open_lock);
Joe Perches74f63f42010-03-10 15:20:58 -08003234 if (lock_fdc(drive, true)) {
Jiri Slaby8516a502009-06-30 11:41:44 -07003235 mutex_unlock(&open_lock);
3236 return -EINTR;
3237 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 floppy_type[type] = *g;
3239 floppy_type[type].name = "user format";
3240 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3241 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3242 floppy_type[type].size + 1;
3243 process_fd_request();
3244 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3245 struct block_device *bdev = opened_bdev[cnt];
3246 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3247 continue;
NeilBrown93b270f2011-02-24 17:25:47 +11003248 __invalidate_device(bdev, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003250 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251 } else {
3252 int oldStretch;
Joe Perches52a0d612010-03-10 15:20:53 -08003253
Joe Perches74f63f42010-03-10 15:20:58 -08003254 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003255 return -EINTR;
Joe Perches4575b552010-03-10 15:20:55 -08003256 if (cmd != FDDEFPRM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257 /* notice a disk change immediately, else
3258 * we lose our settings immediately*/
Joe Perches74f63f42010-03-10 15:20:58 -08003259 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003260 return -EINTR;
3261 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 oldStretch = g->stretch;
3263 user_params[drive] = *g;
3264 if (buffer_drive == drive)
3265 SUPBOUND(buffer_max, user_params[drive].sect);
3266 current_type[drive] = &user_params[drive];
3267 floppy_sizes[drive] = user_params[drive].size;
3268 if (cmd == FDDEFPRM)
3269 DRS->keep_data = -1;
3270 else
3271 DRS->keep_data = 1;
3272 /* invalidation. Invalidate only when needed, i.e.
3273 * when there are already sectors in the buffer cache
3274 * whose number will change. This is useful, because
3275 * mtools often changes the geometry of the disk after
3276 * looking at the boot block */
3277 if (DRS->maxblock > user_params[drive].sect ||
3278 DRS->maxtrack ||
3279 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003280 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281 invalidate_drive(bdev);
3282 else
3283 process_fd_request();
3284 }
3285 return 0;
3286}
3287
3288/* handle obsolete ioctl's */
Stephen Hemminger21af5442010-06-15 13:21:11 +02003289static unsigned int ioctl_table[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 FDCLRPRM,
3291 FDSETPRM,
3292 FDDEFPRM,
3293 FDGETPRM,
3294 FDMSGON,
3295 FDMSGOFF,
3296 FDFMTBEG,
3297 FDFMTTRK,
3298 FDFMTEND,
3299 FDSETEMSGTRESH,
3300 FDFLUSH,
3301 FDSETMAXERRS,
3302 FDGETMAXERRS,
3303 FDGETDRVTYP,
3304 FDSETDRVPRM,
3305 FDGETDRVPRM,
3306 FDGETDRVSTAT,
3307 FDPOLLDRVSTAT,
3308 FDRESET,
3309 FDGETFDCSTAT,
3310 FDWERRORCLR,
3311 FDWERRORGET,
3312 FDRAWCMD,
3313 FDEJECT,
3314 FDTWADDLE
3315};
3316
Stephen Hemminger21af5442010-06-15 13:21:11 +02003317static int normalize_ioctl(unsigned int *cmd, int *size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318{
3319 int i;
3320
3321 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3322 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3323 *size = _IOC_SIZE(*cmd);
3324 *cmd = ioctl_table[i];
3325 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003326 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 return -EFAULT;
3328 }
3329 return 0;
3330 }
3331 }
3332 return -EINVAL;
3333}
3334
3335static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3336{
3337 if (type)
3338 *g = &floppy_type[type];
3339 else {
Joe Perches74f63f42010-03-10 15:20:58 -08003340 if (lock_fdc(drive, false))
Joe Perches52a0d612010-03-10 15:20:53 -08003341 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003342 if (poll_drive(false, 0) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003343 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 process_fd_request();
3345 *g = current_type[drive];
3346 }
3347 if (!*g)
3348 return -ENODEV;
3349 return 0;
3350}
3351
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003352static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3353{
3354 int drive = (long)bdev->bd_disk->private_data;
3355 int type = ITYPE(drive_state[drive].fd_device);
3356 struct floppy_struct *g;
3357 int ret;
3358
3359 ret = get_floppy_geometry(drive, type, &g);
3360 if (ret)
3361 return ret;
3362
3363 geo->heads = g->head;
3364 geo->sectors = g->sect;
3365 geo->cylinders = g->track;
3366 return 0;
3367}
3368
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003369static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 unsigned long param)
3371{
Al Viroa4af9b42008-03-02 09:27:55 -05003372 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003373 int type = ITYPE(UDRS->fd_device);
3374 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 int ret;
3376 int size;
3377 union inparam {
3378 struct floppy_struct g; /* geometry */
3379 struct format_descr f;
3380 struct floppy_max_errors max_errors;
3381 struct floppy_drive_params dp;
3382 } inparam; /* parameters coming from user space */
Joe Perches724ee622010-03-10 15:21:11 -08003383 const void *outparam; /* parameters passed back to user space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384
3385 /* convert compatibility eject ioctls into floppy eject ioctl.
3386 * We do this in order to provide a means to eject floppy disks before
3387 * installing the new fdutils package */
3388 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003389 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390 DPRINT("obsolete eject ioctl\n");
3391 DPRINT("please use floppycontrol --eject\n");
3392 cmd = FDEJECT;
3393 }
3394
Joe Perchesa81ee542010-03-10 15:20:46 -08003395 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 return -EINVAL;
3397
Joe Perchesa81ee542010-03-10 15:20:46 -08003398 /* convert the old style command into a new style command */
Joe Perches4575b552010-03-10 15:20:55 -08003399 ret = normalize_ioctl(&cmd, &size);
3400 if (ret)
3401 return ret;
Joe Perchesa81ee542010-03-10 15:20:46 -08003402
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 /* permission checks */
Joe Perches0aad92c2010-03-10 15:21:10 -08003404 if (((cmd & 0x40) && !(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL))) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3406 return -EPERM;
3407
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003408 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3409 return -EINVAL;
3410
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 /* copyin */
Joe Perchesb87c9e02010-03-10 15:20:50 -08003412 memset(&inparam, 0, sizeof(inparam));
Joe Perches4575b552010-03-10 15:20:55 -08003413 if (_IOC_DIR(cmd) & _IOC_WRITE) {
3414 ret = fd_copyin((void __user *)param, &inparam, size);
3415 if (ret)
3416 return ret;
3417 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418
Joe Perchesda273652010-03-10 15:20:52 -08003419 switch (cmd) {
3420 case FDEJECT:
3421 if (UDRS->fd_ref != 1)
3422 /* somebody else has this drive open */
3423 return -EBUSY;
Joe Perches74f63f42010-03-10 15:20:58 -08003424 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003425 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426
Joe Perchesda273652010-03-10 15:20:52 -08003427 /* do the actual eject. Fails on
3428 * non-Sparc architectures */
3429 ret = fd_eject(UNIT(drive));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430
Joe Perchese0298532010-03-10 15:20:55 -08003431 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3432 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Joe Perchesda273652010-03-10 15:20:52 -08003433 process_fd_request();
3434 return ret;
3435 case FDCLRPRM:
Joe Perches74f63f42010-03-10 15:20:58 -08003436 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003437 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003438 current_type[drive] = NULL;
3439 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3440 UDRS->keep_data = 0;
3441 return invalidate_drive(bdev);
3442 case FDSETPRM:
3443 case FDDEFPRM:
3444 return set_geometry(cmd, &inparam.g, drive, type, bdev);
3445 case FDGETPRM:
Joe Perches4575b552010-03-10 15:20:55 -08003446 ret = get_floppy_geometry(drive, type,
Joe Perches724ee622010-03-10 15:21:11 -08003447 (struct floppy_struct **)&outparam);
Joe Perches4575b552010-03-10 15:20:55 -08003448 if (ret)
3449 return ret;
Joe Perchesda273652010-03-10 15:20:52 -08003450 break;
3451 case FDMSGON:
3452 UDP->flags |= FTD_MSG;
3453 return 0;
3454 case FDMSGOFF:
3455 UDP->flags &= ~FTD_MSG;
3456 return 0;
3457 case FDFMTBEG:
Joe Perches74f63f42010-03-10 15:20:58 -08003458 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003459 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003460 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003461 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003462 ret = UDRS->flags;
3463 process_fd_request();
3464 if (ret & FD_VERIFY)
3465 return -ENODEV;
3466 if (!(ret & FD_DISK_WRITABLE))
3467 return -EROFS;
3468 return 0;
3469 case FDFMTTRK:
3470 if (UDRS->fd_ref != 1)
3471 return -EBUSY;
3472 return do_format(drive, &inparam.f);
3473 case FDFMTEND:
3474 case FDFLUSH:
Joe Perches74f63f42010-03-10 15:20:58 -08003475 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003476 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003477 return invalidate_drive(bdev);
3478 case FDSETEMSGTRESH:
3479 UDP->max_errors.reporting = (unsigned short)(param & 0x0f);
3480 return 0;
3481 case FDGETMAXERRS:
Joe Perches724ee622010-03-10 15:21:11 -08003482 outparam = &UDP->max_errors;
Joe Perchesda273652010-03-10 15:20:52 -08003483 break;
3484 case FDSETMAXERRS:
3485 UDP->max_errors = inparam.max_errors;
3486 break;
3487 case FDGETDRVTYP:
3488 outparam = drive_name(type, drive);
Joe Perches724ee622010-03-10 15:21:11 -08003489 SUPBOUND(size, strlen((const char *)outparam) + 1);
Joe Perchesda273652010-03-10 15:20:52 -08003490 break;
3491 case FDSETDRVPRM:
3492 *UDP = inparam.dp;
3493 break;
3494 case FDGETDRVPRM:
Joe Perches724ee622010-03-10 15:21:11 -08003495 outparam = UDP;
Joe Perchesda273652010-03-10 15:20:52 -08003496 break;
3497 case FDPOLLDRVSTAT:
Joe Perches74f63f42010-03-10 15:20:58 -08003498 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003499 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003500 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003501 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003502 process_fd_request();
3503 /* fall through */
3504 case FDGETDRVSTAT:
Joe Perches724ee622010-03-10 15:21:11 -08003505 outparam = UDRS;
Joe Perchesda273652010-03-10 15:20:52 -08003506 break;
3507 case FDRESET:
Joe Perches74f63f42010-03-10 15:20:58 -08003508 return user_reset_fdc(drive, (int)param, true);
Joe Perchesda273652010-03-10 15:20:52 -08003509 case FDGETFDCSTAT:
Joe Perches724ee622010-03-10 15:21:11 -08003510 outparam = UFDCS;
Joe Perchesda273652010-03-10 15:20:52 -08003511 break;
3512 case FDWERRORCLR:
3513 memset(UDRWE, 0, sizeof(*UDRWE));
3514 return 0;
3515 case FDWERRORGET:
Joe Perches724ee622010-03-10 15:21:11 -08003516 outparam = UDRWE;
Joe Perchesda273652010-03-10 15:20:52 -08003517 break;
3518 case FDRAWCMD:
3519 if (type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 return -EINVAL;
Joe Perches74f63f42010-03-10 15:20:58 -08003521 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003522 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003523 set_floppy(drive);
Joe Perches4575b552010-03-10 15:20:55 -08003524 i = raw_cmd_ioctl(cmd, (void __user *)param);
3525 if (i == -EINTR)
3526 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003527 process_fd_request();
3528 return i;
3529 case FDTWADDLE:
Joe Perches74f63f42010-03-10 15:20:58 -08003530 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003531 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003532 twaddle();
3533 process_fd_request();
3534 return 0;
3535 default:
3536 return -EINVAL;
3537 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538
3539 if (_IOC_DIR(cmd) & _IOC_READ)
3540 return fd_copyout((void __user *)param, outparam, size);
Joe Perchesda273652010-03-10 15:20:52 -08003541
3542 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543}
3544
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003545static int fd_ioctl(struct block_device *bdev, fmode_t mode,
3546 unsigned int cmd, unsigned long param)
3547{
3548 int ret;
3549
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003550 mutex_lock(&floppy_mutex);
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003551 ret = fd_locked_ioctl(bdev, mode, cmd, param);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003552 mutex_unlock(&floppy_mutex);
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003553
3554 return ret;
3555}
3556
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557static void __init config_types(void)
3558{
Joe Perchesb46df352010-03-10 15:20:46 -08003559 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 int drive;
3561
3562 /* read drive info out of physical CMOS */
3563 drive = 0;
3564 if (!UDP->cmos)
3565 UDP->cmos = FLOPPY0_TYPE;
3566 drive = 1;
3567 if (!UDP->cmos && FLOPPY1_TYPE)
3568 UDP->cmos = FLOPPY1_TYPE;
3569
Jesper Juhl06f748c2007-10-16 23:30:57 -07003570 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571
3572 for (drive = 0; drive < N_DRIVE; drive++) {
3573 unsigned int type = UDP->cmos;
3574 struct floppy_drive_params *params;
3575 const char *name = NULL;
3576 static char temparea[32];
3577
Tobias Klauser945f3902006-01-08 01:05:11 -08003578 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 params = &default_drive_params[type].params;
3580 if (type) {
3581 name = default_drive_params[type].name;
3582 allowed_drive_mask |= 1 << drive;
3583 } else
3584 allowed_drive_mask &= ~(1 << drive);
3585 } else {
3586 params = &default_drive_params[0].params;
3587 sprintf(temparea, "unknown type %d (usb?)", type);
3588 name = temparea;
3589 }
3590 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003591 const char *prepend;
3592 if (!has_drive) {
3593 prepend = "";
3594 has_drive = true;
3595 pr_info("Floppy drive(s):");
3596 } else {
3597 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 }
Joe Perchesb46df352010-03-10 15:20:46 -08003599
3600 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601 }
3602 *UDP = *params;
3603 }
Joe Perchesb46df352010-03-10 15:20:46 -08003604
3605 if (has_drive)
3606 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607}
3608
Al Viroa4af9b42008-03-02 09:27:55 -05003609static int floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610{
Al Viroa4af9b42008-03-02 09:27:55 -05003611 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003613 mutex_lock(&floppy_mutex);
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003614 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 if (UDRS->fd_ref < 0)
3616 UDRS->fd_ref = 0;
3617 else if (!UDRS->fd_ref--) {
3618 DPRINT("floppy_release with fd_ref == 0");
3619 UDRS->fd_ref = 0;
3620 }
3621 if (!UDRS->fd_ref)
3622 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003623 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003624 mutex_unlock(&floppy_mutex);
Ingo Molnar3e541a42006-07-03 00:24:23 -07003625
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 return 0;
3627}
3628
3629/*
3630 * floppy_open check for aliasing (/dev/fd0 can be the same as
3631 * /dev/PS0 etc), and disallows simultaneous access to the same
3632 * drive with different device numbers.
3633 */
Al Viroa4af9b42008-03-02 09:27:55 -05003634static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635{
Al Viroa4af9b42008-03-02 09:27:55 -05003636 int drive = (long)bdev->bd_disk->private_data;
3637 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 int try;
3639 int res = -EBUSY;
3640 char *tmp;
3641
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003642 mutex_lock(&floppy_mutex);
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003643 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003645 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 goto out2;
3647
3648 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
Joe Perchese0298532010-03-10 15:20:55 -08003649 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3650 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 }
3652
Al Viroa4af9b42008-03-02 09:27:55 -05003653 if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 goto out2;
3655
Al Viroa4af9b42008-03-02 09:27:55 -05003656 if (mode & FMODE_EXCL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 UDRS->fd_ref = -1;
3658 else
3659 UDRS->fd_ref++;
3660
Al Viroa4af9b42008-03-02 09:27:55 -05003661 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662
3663 res = -ENXIO;
3664
3665 if (!floppy_track_buffer) {
3666 /* if opening an ED drive, reserve a big buffer,
3667 * else reserve a small one */
3668 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3669 try = 64; /* Only 48 actually useful */
3670 else
3671 try = 32; /* Only 24 actually useful */
3672
3673 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3674 if (!tmp && !floppy_track_buffer) {
3675 try >>= 1; /* buffer only one side */
3676 INFBOUND(try, 16);
3677 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3678 }
Joe Perchesa81ee542010-03-10 15:20:46 -08003679 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681 if (!tmp && !floppy_track_buffer) {
3682 DPRINT("Unable to allocate DMA memory\n");
3683 goto out;
3684 }
3685 if (floppy_track_buffer) {
3686 if (tmp)
3687 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3688 } else {
3689 buffer_min = buffer_max = -1;
3690 floppy_track_buffer = tmp;
3691 max_buffer_sectors = try;
3692 }
3693 }
3694
Al Viroa4af9b42008-03-02 09:27:55 -05003695 new_dev = MINOR(bdev->bd_dev);
3696 UDRS->fd_device = new_dev;
3697 set_capacity(disks[drive], floppy_sizes[new_dev]);
3698 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699 if (buffer_drive == drive)
3700 buffer_track = -1;
3701 }
3702
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 if (UFDCS->rawcmd == 1)
3704 UFDCS->rawcmd = 2;
3705
Al Viroa4af9b42008-03-02 09:27:55 -05003706 if (!(mode & FMODE_NDELAY)) {
3707 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 UDRS->last_checked = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003709 check_disk_change(bdev);
Joe Perchese0298532010-03-10 15:20:55 -08003710 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 goto out;
3712 }
3713 res = -EROFS;
Joe Perchese0298532010-03-10 15:20:55 -08003714 if ((mode & FMODE_WRITE) &&
3715 !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716 goto out;
3717 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003718 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003719 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 return 0;
3721out:
3722 if (UDRS->fd_ref < 0)
3723 UDRS->fd_ref = 0;
3724 else
3725 UDRS->fd_ref--;
3726 if (!UDRS->fd_ref)
3727 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003729 mutex_unlock(&open_lock);
Arnd Bergmann2a48fc02010-06-02 14:28:52 +02003730 mutex_unlock(&floppy_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731 return res;
3732}
3733
3734/*
3735 * Check if the disk has been changed or if a change has been faked.
3736 */
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003737static unsigned int floppy_check_events(struct gendisk *disk,
3738 unsigned int clearing)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739{
3740 int drive = (long)disk->private_data;
3741
Joe Perchese0298532010-03-10 15:20:55 -08003742 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3743 test_bit(FD_VERIFY_BIT, &UDRS->flags))
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003744 return DISK_EVENT_MEDIA_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003746 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Joe Perches74f63f42010-03-10 15:20:58 -08003747 lock_fdc(drive, false);
3748 poll_drive(false, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 }
3751
Joe Perchese0298532010-03-10 15:20:55 -08003752 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3753 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754 test_bit(drive, &fake_change) ||
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003755 drive_no_geom(drive))
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003756 return DISK_EVENT_MEDIA_CHANGE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 return 0;
3758}
3759
3760/*
3761 * This implements "read block 0" for floppy_revalidate().
3762 * Needed for format autodetection, checking whether there is
3763 * a disk in the drive, and whether that disk is writable.
3764 */
3765
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003766static void floppy_rb0_complete(struct bio *bio, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 complete((struct completion *)bio->bi_private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769}
3770
3771static int __floppy_read_block_0(struct block_device *bdev)
3772{
3773 struct bio bio;
3774 struct bio_vec bio_vec;
3775 struct completion complete;
3776 struct page *page;
3777 size_t size;
3778
3779 page = alloc_page(GFP_NOIO);
3780 if (!page) {
3781 process_fd_request();
3782 return -ENOMEM;
3783 }
3784
3785 size = bdev->bd_block_size;
3786 if (!size)
3787 size = 1024;
3788
3789 bio_init(&bio);
3790 bio.bi_io_vec = &bio_vec;
3791 bio_vec.bv_page = page;
3792 bio_vec.bv_len = size;
3793 bio_vec.bv_offset = 0;
3794 bio.bi_vcnt = 1;
3795 bio.bi_idx = 0;
3796 bio.bi_size = size;
3797 bio.bi_bdev = bdev;
3798 bio.bi_sector = 0;
Muthu Kumar9354f1b2012-03-05 14:59:16 -08003799 bio.bi_flags = (1 << BIO_QUIET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 init_completion(&complete);
3801 bio.bi_private = &complete;
3802 bio.bi_end_io = floppy_rb0_complete;
3803
3804 submit_bio(READ, &bio);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805 process_fd_request();
3806 wait_for_completion(&complete);
3807
3808 __free_page(page);
3809
3810 return 0;
3811}
3812
3813/* revalidate the floppy disk, i.e. trigger format autodetection by reading
3814 * the bootblock (block 0). "Autodetection" is also needed to check whether
3815 * there is a disk in the drive at all... Thus we also do it for fixed
3816 * geometry formats */
3817static int floppy_revalidate(struct gendisk *disk)
3818{
3819 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820 int cf;
3821 int res = 0;
3822
Joe Perchese0298532010-03-10 15:20:55 -08003823 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3824 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003825 test_bit(drive, &fake_change) ||
3826 drive_no_geom(drive)) {
Stephen Hemminger01b6b672010-06-15 13:21:11 +02003827 if (WARN(atomic_read(&usage_count) == 0,
3828 "VFS: revalidate called on non-open device.\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 return -EFAULT;
Stephen Hemminger01b6b672010-06-15 13:21:11 +02003830
Joe Perches74f63f42010-03-10 15:20:58 -08003831 lock_fdc(drive, false);
Joe Perchese0298532010-03-10 15:20:55 -08003832 cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3833 test_bit(FD_VERIFY_BIT, &UDRS->flags));
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003834 if (!(cf || test_bit(drive, &fake_change) || drive_no_geom(drive))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835 process_fd_request(); /*already done by another thread */
3836 return 0;
3837 }
3838 UDRS->maxblock = 0;
3839 UDRS->maxtrack = 0;
3840 if (buffer_drive == drive)
3841 buffer_track = -1;
3842 clear_bit(drive, &fake_change);
Joe Perchese0298532010-03-10 15:20:55 -08003843 clear_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844 if (cf)
3845 UDRS->generation++;
Pekka Enberg2b51dca2010-11-08 14:44:34 +01003846 if (drive_no_geom(drive)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003847 /* auto-sensing */
3848 res = __floppy_read_block_0(opened_bdev[drive]);
3849 } else {
3850 if (cf)
Joe Perches74f63f42010-03-10 15:20:58 -08003851 poll_drive(false, FD_RAW_NEED_DISK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852 process_fd_request();
3853 }
3854 }
3855 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
3856 return res;
3857}
3858
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07003859static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07003860 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05003861 .open = floppy_open,
3862 .release = floppy_release,
Arnd Bergmann8a6cfeb2010-07-08 10:18:46 +02003863 .ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003864 .getgeo = fd_getgeo,
Tejun Heo1a8a74f2011-03-09 19:54:27 +01003865 .check_events = floppy_check_events,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003866 .revalidate_disk = floppy_revalidate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869/*
3870 * Floppy Driver initialization
3871 * =============================
3872 */
3873
3874/* Determine the floppy disk controller type */
3875/* This routine was written by David C. Niemi */
3876static char __init get_fdc_version(void)
3877{
3878 int r;
3879
3880 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
3881 if (FDCS->reset)
3882 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003883 r = result();
3884 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885 return FDC_NONE; /* No FDC present ??? */
3886 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003887 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3889 }
3890 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003891 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3892 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 return FDC_UNKNOWN;
3894 }
3895
3896 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003897 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003898 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3899 }
3900
3901 output_byte(FD_PERPENDICULAR);
3902 if (need_more_output() == MORE_OUTPUT) {
3903 output_byte(0);
3904 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003905 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906 return FDC_82072A; /* 82072A as found on Sparcs. */
3907 }
3908
3909 output_byte(FD_UNLOCK);
3910 r = result();
3911 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003912 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003913 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914 * LOCK/UNLOCK */
3915 }
3916 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003917 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3918 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919 return FDC_UNKNOWN;
3920 }
3921 output_byte(FD_PARTID);
3922 r = result();
3923 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003924 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3925 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926 return FDC_UNKNOWN;
3927 }
3928 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003929 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930 return FDC_82077; /* Revised 82077AA passes all the tests */
3931 }
3932 switch (reply_buffer[0] >> 5) {
3933 case 0x0:
3934 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08003935 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936 return FDC_82078;
3937 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08003938 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003939 return FDC_82078;
3940 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08003941 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942 return FDC_S82078B;
3943 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08003944 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003945 return FDC_87306;
3946 default:
Joe Perchesb46df352010-03-10 15:20:46 -08003947 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
3948 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949 return FDC_82078_UNKN;
3950 }
3951} /* get_fdc_version */
3952
3953/* lilo configuration */
3954
3955static void __init floppy_set_flags(int *ints, int param, int param2)
3956{
3957 int i;
3958
3959 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
3960 if (param)
3961 default_drive_params[i].params.flags |= param2;
3962 else
3963 default_drive_params[i].params.flags &= ~param2;
3964 }
3965 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
3966}
3967
3968static void __init daring(int *ints, int param, int param2)
3969{
3970 int i;
3971
3972 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
3973 if (param) {
3974 default_drive_params[i].params.select_delay = 0;
3975 default_drive_params[i].params.flags |=
3976 FD_SILENT_DCL_CLEAR;
3977 } else {
3978 default_drive_params[i].params.select_delay =
3979 2 * HZ / 100;
3980 default_drive_params[i].params.flags &=
3981 ~FD_SILENT_DCL_CLEAR;
3982 }
3983 }
3984 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
3985}
3986
3987static void __init set_cmos(int *ints, int dummy, int dummy2)
3988{
3989 int current_drive = 0;
3990
3991 if (ints[0] != 2) {
3992 DPRINT("wrong number of parameters for CMOS\n");
3993 return;
3994 }
3995 current_drive = ints[1];
3996 if (current_drive < 0 || current_drive >= 8) {
3997 DPRINT("bad drive for set_cmos\n");
3998 return;
3999 }
4000#if N_FDC > 1
4001 if (current_drive >= 4 && !FDC2)
4002 FDC2 = 0x370;
4003#endif
4004 DP->cmos = ints[2];
4005 DPRINT("setting CMOS code to %d\n", ints[2]);
4006}
4007
4008static struct param_table {
4009 const char *name;
4010 void (*fn) (int *ints, int param, int param2);
4011 int *var;
4012 int def_param;
4013 int param2;
4014} config_params[] __initdata = {
4015 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4016 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4017 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4018 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4019 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4020 {"daring", daring, NULL, 1, 0},
4021#if N_FDC > 1
4022 {"two_fdc", NULL, &FDC2, 0x370, 0},
4023 {"one_fdc", NULL, &FDC2, 0, 0},
4024#endif
4025 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4026 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4027 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4028 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4029 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4030 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4031 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4032 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4033 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4034 {"nofifo", NULL, &no_fifo, 0x20, 0},
4035 {"usefifo", NULL, &no_fifo, 0, 0},
4036 {"cmos", set_cmos, NULL, 0, 0},
4037 {"slow", NULL, &slow_floppy, 1, 0},
4038 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4039 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4040 {"L40SX", NULL, &print_unex, 0, 0}
4041
4042 EXTRA_FLOPPY_PARAMS
4043};
4044
4045static int __init floppy_setup(char *str)
4046{
4047 int i;
4048 int param;
4049 int ints[11];
4050
4051 str = get_options(str, ARRAY_SIZE(ints), ints);
4052 if (str) {
4053 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4054 if (strcmp(str, config_params[i].name) == 0) {
4055 if (ints[0])
4056 param = ints[1];
4057 else
4058 param = config_params[i].def_param;
4059 if (config_params[i].fn)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004060 config_params[i].fn(ints, param,
4061 config_params[i].
4062 param2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 if (config_params[i].var) {
4064 DPRINT("%s=%d\n", str, param);
4065 *config_params[i].var = param;
4066 }
4067 return 1;
4068 }
4069 }
4070 }
4071 if (str) {
4072 DPRINT("unknown floppy option [%s]\n", str);
4073
4074 DPRINT("allowed options are:");
4075 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004076 pr_cont(" %s", config_params[i].name);
4077 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078 } else
4079 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004080 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081 return 0;
4082}
4083
4084static int have_no_fdc = -ENODEV;
4085
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004086static ssize_t floppy_cmos_show(struct device *dev,
4087 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004088{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004089 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004090 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004091
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004092 drive = p->id;
4093 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004094}
Joe Perches48c8cee2010-03-10 15:20:45 -08004095
Stephen Hemmingerbe1c0fb2010-06-15 13:21:11 +02004096static DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004097
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098static void floppy_device_release(struct device *dev)
4099{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100}
4101
Frans Popc90cd332009-07-25 22:24:54 +02004102static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004103{
4104 int fdc;
4105
4106 for (fdc = 0; fdc < N_FDC; fdc++)
4107 if (FDCS->address != -1)
Joe Perches74f63f42010-03-10 15:20:58 -08004108 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004109
4110 return 0;
4111}
4112
Alexey Dobriyan47145212009-12-14 18:00:08 -08004113static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004114 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004115 .restore = floppy_resume,
4116};
4117
4118static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004119 .driver = {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004120 .name = "floppy",
4121 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004122 },
4123};
4124
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004125static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126
4127static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4128{
4129 int drive = (*part & 3) | ((*part & 0x80) >> 5);
4130 if (drive >= N_DRIVE ||
4131 !(allowed_drive_mask & (1 << drive)) ||
4132 fdc_state[FDC(drive)].version == FDC_NONE)
4133 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004134 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135 return NULL;
4136 *part = 0;
4137 return get_disk(disks[drive]);
4138}
4139
4140static int __init floppy_init(void)
4141{
4142 int i, unit, drive;
4143 int err, dr;
4144
Stephen Hemminger285203c2010-06-15 13:21:11 +02004145 set_debugt();
4146 interruptjiffies = resultjiffies = jiffies;
4147
Kumar Gala68e1ee62008-09-22 14:41:31 -07004148#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004149 if (check_legacy_ioport(FDC1))
4150 return -ENODEV;
4151#endif
4152
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153 raw_cmd = NULL;
4154
4155 for (dr = 0; dr < N_DRIVE; dr++) {
4156 disks[dr] = alloc_disk(1);
4157 if (!disks[dr]) {
4158 err = -ENOMEM;
4159 goto out_put_disk;
4160 }
4161
Jens Axboe48821182010-09-22 09:32:36 +02004162 disks[dr]->queue = blk_init_queue(do_fd_request, &floppy_lock);
4163 if (!disks[dr]->queue) {
4164 err = -ENOMEM;
4165 goto out_put_disk;
4166 }
4167
4168 blk_queue_max_hw_sectors(disks[dr]->queue, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169 disks[dr]->major = FLOPPY_MAJOR;
4170 disks[dr]->first_minor = TOMINOR(dr);
4171 disks[dr]->fops = &floppy_fops;
4172 sprintf(disks[dr]->disk_name, "fd%d", dr);
4173
4174 init_timer(&motor_off_timer[dr]);
4175 motor_off_timer[dr].data = dr;
4176 motor_off_timer[dr].function = motor_off_callback;
4177 }
4178
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179 err = register_blkdev(FLOPPY_MAJOR, "fd");
4180 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004181 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004183 err = platform_driver_register(&floppy_driver);
4184 if (err)
4185 goto out_unreg_blkdev;
4186
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4188 floppy_find, NULL, NULL);
4189
4190 for (i = 0; i < 256; i++)
4191 if (ITYPE(i))
4192 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4193 else
4194 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4195
Joe Perches73507e62010-03-10 15:21:03 -08004196 reschedule_timeout(MAXTIMEOUT, "floppy init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197 config_types();
4198
4199 for (i = 0; i < N_FDC; i++) {
4200 fdc = i;
Joe Perchesb87c9e02010-03-10 15:20:50 -08004201 memset(FDCS, 0, sizeof(*FDCS));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202 FDCS->dtr = -1;
4203 FDCS->dor = 0x4;
4204#if defined(__sparc__) || defined(__mc68000__)
Joe Perches96534f12010-03-10 15:20:51 -08004205 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206#ifdef __mc68000__
4207 if (MACH_IS_SUN3X)
4208#endif
4209 FDCS->version = FDC_82072A;
4210#endif
4211 }
4212
4213 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214 fdc_state[0].address = FDC1;
4215 if (fdc_state[0].address == -1) {
Carsten Emde6c4867f2011-09-21 10:22:11 +02004216 del_timer_sync(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 err = -ENODEV;
4218 goto out_unreg_region;
4219 }
4220#if N_FDC > 1
4221 fdc_state[1].address = FDC2;
4222#endif
4223
4224 fdc = 0; /* reset fdc in case of unexpected interrupt */
4225 err = floppy_grab_irq_and_dma();
4226 if (err) {
Carsten Emde6c4867f2011-09-21 10:22:11 +02004227 del_timer_sync(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228 err = -EBUSY;
4229 goto out_unreg_region;
4230 }
4231
4232 /* initialise drive state */
4233 for (drive = 0; drive < N_DRIVE; drive++) {
Joe Perchesb87c9e02010-03-10 15:20:50 -08004234 memset(UDRS, 0, sizeof(*UDRS));
4235 memset(UDRWE, 0, sizeof(*UDRWE));
Joe Perchese0298532010-03-10 15:20:55 -08004236 set_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
4237 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
4238 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239 UDRS->fd_device = -1;
4240 floppy_track_buffer = NULL;
4241 max_buffer_sectors = 0;
4242 }
4243 /*
4244 * Small 10 msec delay to let through any interrupt that
4245 * initialization might have triggered, to not
4246 * confuse detection:
4247 */
4248 msleep(10);
4249
4250 for (i = 0; i < N_FDC; i++) {
4251 fdc = i;
4252 FDCS->driver_version = FD_DRIVER_VERSION;
4253 for (unit = 0; unit < 4; unit++)
4254 FDCS->track[unit] = 0;
4255 if (FDCS->address == -1)
4256 continue;
4257 FDCS->rawcmd = 2;
Joe Perches74f63f42010-03-10 15:20:58 -08004258 if (user_reset_fdc(-1, FD_RESET_ALWAYS, false)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004260 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261 FDCS->address = -1;
4262 FDCS->version = FDC_NONE;
4263 continue;
4264 }
4265 /* Try to determine the floppy controller type */
4266 FDCS->version = get_fdc_version();
4267 if (FDCS->version == FDC_NONE) {
4268 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004269 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 FDCS->address = -1;
4271 continue;
4272 }
4273 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4274 can_use_virtual_dma = 0;
4275
4276 have_no_fdc = 0;
4277 /* Not all FDCs seem to be able to handle the version command
4278 * properly, so force a reset for the standard FDC clones,
4279 * to avoid interrupt garbage.
4280 */
Joe Perches74f63f42010-03-10 15:20:58 -08004281 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282 }
4283 fdc = 0;
Carsten Emde6c4867f2011-09-21 10:22:11 +02004284 del_timer_sync(&fd_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285 current_drive = 0;
Joe Perches29f1c782010-03-10 15:21:00 -08004286 initialized = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 if (have_no_fdc) {
4288 DPRINT("no floppy controllers found\n");
4289 err = have_no_fdc;
4290 goto out_flush_work;
4291 }
4292
Linus Torvalds1da177e2005-04-16 15:20:36 -07004293 for (drive = 0; drive < N_DRIVE; drive++) {
4294 if (!(allowed_drive_mask & (1 << drive)))
4295 continue;
4296 if (fdc_state[FDC(drive)].version == FDC_NONE)
4297 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004298
4299 floppy_device[drive].name = floppy_device_name;
4300 floppy_device[drive].id = drive;
4301 floppy_device[drive].dev.release = floppy_device_release;
4302
4303 err = platform_device_register(&floppy_device[drive]);
4304 if (err)
4305 goto out_flush_work;
4306
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004307 err = device_create_file(&floppy_device[drive].dev,
4308 &dev_attr_cmos);
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004309 if (err)
4310 goto out_unreg_platform_dev;
4311
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312 /* to be cleaned up... */
4313 disks[drive]->private_data = (void *)(long)drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004315 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 add_disk(disks[drive]);
4317 }
4318
4319 return 0;
4320
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004321out_unreg_platform_dev:
4322 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323out_flush_work:
Tejun Heo8aa0f412010-12-24 15:59:06 +01004324 flush_work_sync(&floppy_work);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004325 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326 floppy_release_irq_and_dma();
4327out_unreg_region:
4328 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004329 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330out_unreg_blkdev:
4331 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332out_put_disk:
4333 while (dr--) {
Carsten Emde6c4867f2011-09-21 10:22:11 +02004334 del_timer_sync(&motor_off_timer[dr]);
Vivek Goyal3f9a5aa2012-02-08 20:03:38 +01004335 if (disks[dr]->queue) {
Jens Axboe48821182010-09-22 09:32:36 +02004336 blk_cleanup_queue(disks[dr]->queue);
Vivek Goyal3f9a5aa2012-02-08 20:03:38 +01004337 /*
4338 * put_disk() is not paired with add_disk() and
4339 * will put queue reference one extra time. fix it.
4340 */
4341 disks[dr]->queue = NULL;
4342 }
Linus Torvaldsc093ee42010-11-05 17:45:59 -07004343 put_disk(disks[dr]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 }
4345 return err;
4346}
4347
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004348static const struct io_region {
4349 int offset;
4350 int size;
4351} io_regions[] = {
4352 { 2, 1 },
4353 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4354 { 4, 2 },
4355 /* address + 6 is reserved, and may be taken by IDE.
4356 * Unfortunately, Adaptec doesn't know this :-(, */
4357 { 7, 1 },
4358};
4359
4360static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4361{
4362 while (p != io_regions) {
4363 p--;
4364 release_region(FDCS->address + p->offset, p->size);
4365 }
4366}
4367
4368#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4369
4370static int floppy_request_regions(int fdc)
4371{
4372 const struct io_region *p;
4373
4374 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004375 if (!request_region(FDCS->address + p->offset,
4376 p->size, "floppy")) {
4377 DPRINT("Floppy io-port 0x%04lx in use\n",
4378 FDCS->address + p->offset);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004379 floppy_release_allocated_regions(fdc, p);
4380 return -EBUSY;
4381 }
4382 }
4383 return 0;
4384}
4385
4386static void floppy_release_regions(int fdc)
4387{
4388 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4389}
4390
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391static int floppy_grab_irq_and_dma(void)
4392{
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004393 if (atomic_inc_return(&usage_count) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394 return 0;
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004395
4396 /*
4397 * We might have scheduled a free_irq(), wait it to
4398 * drain first:
4399 */
Tejun Heo8aa0f412010-12-24 15:59:06 +01004400 flush_work_sync(&floppy_work);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004401
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402 if (fd_request_irq()) {
4403 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4404 FLOPPY_IRQ);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004405 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406 return -1;
4407 }
4408 if (fd_request_dma()) {
4409 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4410 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004411 if (can_use_virtual_dma & 2)
4412 use_virtual_dma = can_use_virtual_dma = 1;
4413 if (!(can_use_virtual_dma & 1)) {
4414 fd_free_irq();
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004415 atomic_dec(&usage_count);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004416 return -1;
4417 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418 }
4419
4420 for (fdc = 0; fdc < N_FDC; fdc++) {
4421 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004422 if (floppy_request_regions(fdc))
4423 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 }
4425 }
4426 for (fdc = 0; fdc < N_FDC; fdc++) {
4427 if (FDCS->address != -1) {
4428 reset_fdc_info(1);
4429 fd_outb(FDCS->dor, FD_DOR);
4430 }
4431 }
4432 fdc = 0;
4433 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4434
4435 for (fdc = 0; fdc < N_FDC; fdc++)
4436 if (FDCS->address != -1)
4437 fd_outb(FDCS->dor, FD_DOR);
4438 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004439 * The driver will try and free resources and relies on us
4440 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 */
4442 fdc = 0;
4443 irqdma_allocated = 1;
4444 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004445cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 fd_free_irq();
4447 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004448 while (--fdc >= 0)
4449 floppy_release_regions(fdc);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004450 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 return -1;
4452}
4453
4454static void floppy_release_irq_and_dma(void)
4455{
4456 int old_fdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457#ifndef __sparc__
4458 int drive;
4459#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 long tmpsize;
4461 unsigned long tmpaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004463 if (!atomic_dec_and_test(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464 return;
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004465
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 if (irqdma_allocated) {
4467 fd_disable_dma();
4468 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004469 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 irqdma_allocated = 0;
4471 }
4472 set_dor(0, ~0, 8);
4473#if N_FDC > 1
4474 set_dor(1, ~8, 0);
4475#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476
4477 if (floppy_track_buffer && max_buffer_sectors) {
4478 tmpsize = max_buffer_sectors * 1024;
4479 tmpaddr = (unsigned long)floppy_track_buffer;
4480 floppy_track_buffer = NULL;
4481 max_buffer_sectors = 0;
4482 buffer_min = buffer_max = -1;
4483 fd_dma_mem_free(tmpaddr, tmpsize);
4484 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485#ifndef __sparc__
4486 for (drive = 0; drive < N_FDC * 4; drive++)
4487 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004488 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489#endif
4490
4491 if (timer_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004492 pr_info("floppy timer still active:%s\n", timeout_message);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004494 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004495 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004496 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497 old_fdc = fdc;
4498 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004499 if (FDCS->address != -1)
4500 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 fdc = old_fdc;
4502}
4503
4504#ifdef MODULE
4505
4506static char *floppy;
4507
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508static void __init parse_floppy_cfg_string(char *cfg)
4509{
4510 char *ptr;
4511
4512 while (*cfg) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004513 ptr = cfg;
4514 while (*cfg && *cfg != ' ' && *cfg != '\t')
4515 cfg++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516 if (*cfg) {
4517 *cfg = '\0';
4518 cfg++;
4519 }
4520 if (*ptr)
4521 floppy_setup(ptr);
4522 }
4523}
4524
Jon Schindler7afea3b2008-04-29 00:59:21 -07004525static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526{
4527 if (floppy)
4528 parse_floppy_cfg_string(floppy);
4529 return floppy_init();
4530}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004531module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532
Jon Schindler7afea3b2008-04-29 00:59:21 -07004533static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534{
4535 int drive;
4536
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4538 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004539 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540
4541 for (drive = 0; drive < N_DRIVE; drive++) {
4542 del_timer_sync(&motor_off_timer[drive]);
4543
4544 if ((allowed_drive_mask & (1 << drive)) &&
4545 fdc_state[FDC(drive)].version != FDC_NONE) {
4546 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004547 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4548 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549 }
Jens Axboe48821182010-09-22 09:32:36 +02004550 blk_cleanup_queue(disks[drive]->queue);
Vivek Goyal4609dff2012-02-08 20:03:39 +01004551
4552 /*
4553 * These disks have not called add_disk(). Don't put down
4554 * queue reference in put_disk().
4555 */
4556 if (!(allowed_drive_mask & (1 << drive)) ||
4557 fdc_state[FDC(drive)].version == FDC_NONE)
4558 disks[drive]->queue = NULL;
4559
Vivek Goyald017bf62010-11-06 08:16:05 -04004560 put_disk(disks[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562
4563 del_timer_sync(&fd_timeout);
4564 del_timer_sync(&fd_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004566 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567 floppy_release_irq_and_dma();
4568
4569 /* eject disk, if any */
4570 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571}
Joe Perches48c8cee2010-03-10 15:20:45 -08004572
Jon Schindler7afea3b2008-04-29 00:59:21 -07004573module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574
4575module_param(floppy, charp, 0);
4576module_param(FLOPPY_IRQ, int, 0);
4577module_param(FLOPPY_DMA, int, 0);
4578MODULE_AUTHOR("Alain L. Knaff");
4579MODULE_SUPPORTED_DEVICE("fd");
4580MODULE_LICENSE("GPL");
4581
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004582/* This doesn't actually get used other than for module information */
4583static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004584 {"PNP0700", 0},
4585 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004586};
Joe Perches48c8cee2010-03-10 15:20:45 -08004587
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004588MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4589
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590#else
4591
4592__setup("floppy=", floppy_setup);
4593module_init(floppy_init)
4594#endif
4595
4596MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);