blob: 1fe5225a38291256bb291177b90a65ab92da9cf1 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/block/floppy.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 * Copyright (C) 1993, 1994 Alain Knaff
6 * Copyright (C) 1998 Alan Cox
7 */
Jesper Juhl06f748c2007-10-16 23:30:57 -07008
Linus Torvalds1da177e2005-04-16 15:20:36 -07009/*
10 * 02.12.91 - Changed to static variables to indicate need for reset
11 * and recalibrate. This makes some things easier (output_byte reset
12 * checking etc), and means less interrupt jumping in case of errors,
13 * so the code is hopefully easier to understand.
14 */
15
16/*
17 * This file is certainly a mess. I've tried my best to get it working,
18 * but I don't like programming floppies, and I have only one anyway.
19 * Urgel. I should check for more errors, and do more graceful error
20 * recovery. Seems there are problems with several drives. I've tried to
21 * correct them. No promises.
22 */
23
24/*
25 * As with hd.c, all routines within this file can (and will) be called
26 * by interrupts, so extreme caution is needed. A hardware interrupt
27 * handler may not sleep, or a kernel panic will happen. Thus I cannot
28 * call "floppy-on" directly, but have to set a special timer interrupt
29 * etc.
30 */
31
32/*
33 * 28.02.92 - made track-buffering routines, based on the routines written
34 * by entropy@wintermute.wpi.edu (Lawrence Foard). Linus.
35 */
36
37/*
38 * Automatic floppy-detection and formatting written by Werner Almesberger
39 * (almesber@nessie.cs.id.ethz.ch), who also corrected some problems with
40 * the floppy-change signal detection.
41 */
42
43/*
44 * 1992/7/22 -- Hennus Bergman: Added better error reporting, fixed
45 * FDC data overrun bug, added some preliminary stuff for vertical
46 * recording support.
47 *
48 * 1992/9/17: Added DMA allocation & DMA functions. -- hhb.
49 *
50 * TODO: Errors are still not counted properly.
51 */
52
53/* 1992/9/20
54 * Modifications for ``Sector Shifting'' by Rob Hooft (hooft@chem.ruu.nl)
55 * modeled after the freeware MS-DOS program fdformat/88 V1.8 by
56 * Christoph H. Hochst\"atter.
57 * I have fixed the shift values to the ones I always use. Maybe a new
58 * ioctl() should be created to be able to modify them.
59 * There is a bug in the driver that makes it impossible to format a
60 * floppy as the first thing after bootup.
61 */
62
63/*
64 * 1993/4/29 -- Linus -- cleaned up the timer handling in the kernel, and
65 * this helped the floppy driver as well. Much cleaner, and still seems to
66 * work.
67 */
68
69/* 1994/6/24 --bbroad-- added the floppy table entries and made
70 * minor modifications to allow 2.88 floppies to be run.
71 */
72
73/* 1994/7/13 -- Paul Vojta -- modified the probing code to allow three or more
74 * disk types.
75 */
76
77/*
78 * 1994/8/8 -- Alain Knaff -- Switched to fdpatch driver: Support for bigger
79 * format bug fixes, but unfortunately some new bugs too...
80 */
81
82/* 1994/9/17 -- Koen Holtman -- added logging of physical floppy write
83 * errors to allow safe writing by specialized programs.
84 */
85
86/* 1995/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks
87 * by defining bit 1 of the "stretch" parameter to mean put sectors on the
88 * opposite side of the disk, leaving the sector IDs alone (i.e. Commodore's
89 * drives are "upside-down").
90 */
91
92/*
93 * 1995/8/26 -- Andreas Busse -- added Mips support.
94 */
95
96/*
97 * 1995/10/18 -- Ralf Baechle -- Portability cleanup; move machine dependent
98 * features to asm/floppy.h.
99 */
100
101/*
James Nelsonb88b0982005-11-08 16:52:12 +0100102 * 1998/1/21 -- Richard Gooch <rgooch@atnf.csiro.au> -- devfs support
103 */
104
105/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 * 1998/05/07 -- Russell King -- More portability cleanups; moved definition of
107 * interrupt and dma channel to asm/floppy.h. Cleaned up some formatting &
108 * use of '0' for NULL.
109 */
110
111/*
112 * 1998/06/07 -- Alan Cox -- Merged the 2.0.34 fixes for resource allocation
113 * failures.
114 */
115
116/*
117 * 1998/09/20 -- David Weinehall -- Added slow-down code for buggy PS/2-drives.
118 */
119
120/*
121 * 1999/08/13 -- Paul Slootman -- floppy stopped working on Alpha after 24
122 * days, 6 hours, 32 minutes and 32 seconds (i.e. MAXINT jiffies; ints were
123 * being used to store jiffies, which are unsigned longs).
124 */
125
126/*
127 * 2000/08/28 -- Arnaldo Carvalho de Melo <acme@conectiva.com.br>
128 * - get rid of check_region
129 * - s/suser/capable/
130 */
131
132/*
133 * 2001/08/26 -- Paul Gortmaker - fix insmod oops on machines with no
134 * floppy controller (lingering task on list after module is gone... boom.)
135 */
136
137/*
138 * 2002/02/07 -- Anton Altaparmakov - Fix io ports reservation to correct range
139 * (0x3f2-0x3f5, 0x3f7). This fix is a bit of a hack but the proper fix
140 * requires many non-obvious changes in arch dependent code.
141 */
142
143/* 2003/07/28 -- Daniele Bellucci <bellucda@tiscali.it>.
144 * Better audit of register_blkdev.
145 */
146
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147#undef FLOPPY_SILENT_DCL_CLEAR
148
149#define REALLY_SLOW_IO
150
151#define DEBUGT 2
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152
Joe Perches891eda82010-03-10 15:21:05 -0800153#define DPRINT(format, args...) \
154 pr_info("floppy%d: " format, current_drive, ##args)
155
156#define DCL_DEBUG /* debug disk change line */
Joe Perches87f530d2010-03-10 15:20:54 -0800157#ifdef DCL_DEBUG
158#define debug_dcl(test, fmt, args...) \
159 do { if ((test) & FD_DEBUG) DPRINT(fmt, ##args); } while (0)
160#else
161#define debug_dcl(test, fmt, args...) \
162 do { if (0) DPRINT(fmt, ##args); } while (0)
163#endif
164
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165/* do print messages for unexpected interrupts */
166static int print_unex = 1;
167#include <linux/module.h>
168#include <linux/sched.h>
169#include <linux/fs.h>
170#include <linux/kernel.h>
171#include <linux/timer.h>
172#include <linux/workqueue.h>
173#define FDPATCHES
174#include <linux/fdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175#include <linux/fd.h>
176#include <linux/hdreg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177#include <linux/errno.h>
178#include <linux/slab.h>
179#include <linux/mm.h>
180#include <linux/bio.h>
181#include <linux/string.h>
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800182#include <linux/jiffies.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183#include <linux/fcntl.h>
184#include <linux/delay.h>
185#include <linux/mc146818rtc.h> /* CMOS defines */
186#include <linux/ioport.h>
187#include <linux/interrupt.h>
188#include <linux/init.h>
Russell Kingd052d1b2005-10-29 19:07:23 +0100189#include <linux/platform_device.h>
Scott James Remnant83f9ef42009-04-02 16:56:47 -0700190#include <linux/mod_devicetable.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191#include <linux/buffer_head.h> /* for invalidate_buffers() */
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800192#include <linux/mutex.h>
Joe Perchesd4937542010-03-10 15:20:44 -0800193#include <linux/io.h>
194#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
196/*
197 * PS/2 floppies have much slower step rates than regular floppies.
198 * It's been recommended that take about 1/4 of the default speed
199 * in some more extreme cases.
200 */
201static int slow_floppy;
202
203#include <asm/dma.h>
204#include <asm/irq.h>
205#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
207static int FLOPPY_IRQ = 6;
208static int FLOPPY_DMA = 2;
209static int can_use_virtual_dma = 2;
210/* =======
211 * can use virtual DMA:
212 * 0 = use of virtual DMA disallowed by config
213 * 1 = use of virtual DMA prescribed by config
214 * 2 = no virtual DMA preference configured. By default try hard DMA,
215 * but fall back on virtual DMA when not enough memory available
216 */
217
218static int use_virtual_dma;
219/* =======
220 * use virtual DMA
221 * 0 using hard DMA
222 * 1 using virtual DMA
223 * This variable is set to virtual when a DMA mem problem arises, and
224 * reset back in floppy_grab_irq_and_dma.
225 * It is not safe to reset it in other circumstances, because the floppy
226 * driver may have several buffers in use at once, and we do currently not
227 * record each buffers capabilities
228 */
229
230static DEFINE_SPINLOCK(floppy_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
232static unsigned short virtual_dma_port = 0x3f0;
David Howells7d12e782006-10-05 14:55:46 +0100233irqreturn_t floppy_interrupt(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234static int set_dor(int fdc, char mask, char data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235
236#define K_64 0x10000 /* 64KB */
237
238/* the following is the mask of allowed drives. By default units 2 and
239 * 3 of both floppy controllers are disabled, because switching on the
240 * motor of these drives causes system hangs on some PCI computers. drive
241 * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
242 * a drive is allowed.
243 *
244 * NOTE: This must come before we include the arch floppy header because
245 * some ports reference this variable from there. -DaveM
246 */
247
248static int allowed_drive_mask = 0x33;
249
250#include <asm/floppy.h>
251
252static int irqdma_allocated;
253
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254#include <linux/blkdev.h>
255#include <linux/blkpg.h>
256#include <linux/cdrom.h> /* for the compatibility eject ioctl */
257#include <linux/completion.h>
258
259static struct request *current_req;
260static struct request_queue *floppy_queue;
Joe Perches48c8cee2010-03-10 15:20:45 -0800261static void do_fd_request(struct request_queue *q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
263#ifndef fd_get_dma_residue
264#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
265#endif
266
267/* Dma Memory related stuff */
268
269#ifndef fd_dma_mem_free
270#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
271#endif
272
273#ifndef fd_dma_mem_alloc
Joe Perches48c8cee2010-03-10 15:20:45 -0800274#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL, get_order(size))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275#endif
276
277static inline void fallback_on_nodma_alloc(char **addr, size_t l)
278{
279#ifdef FLOPPY_CAN_FALLBACK_ON_NODMA
280 if (*addr)
281 return; /* we have the memory */
282 if (can_use_virtual_dma != 2)
283 return; /* no fallback allowed */
Joe Perchesb46df352010-03-10 15:20:46 -0800284 pr_info("DMA memory shortage. Temporarily falling back on virtual DMA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 *addr = (char *)nodma_mem_alloc(l);
286#else
287 return;
288#endif
289}
290
291/* End dma memory related stuff */
292
293static unsigned long fake_change;
Joe Perches29f1c782010-03-10 15:21:00 -0800294static bool initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
Joe Perches48c8cee2010-03-10 15:20:45 -0800296#define ITYPE(x) (((x) >> 2) & 0x1f)
297#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
298#define UNIT(x) ((x) & 0x03) /* drive on fdc */
299#define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700300 /* reverse mapping from unit and fdc to drive */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
Joe Perches48c8cee2010-03-10 15:20:45 -0800303#define DP (&drive_params[current_drive])
304#define DRS (&drive_state[current_drive])
305#define DRWE (&write_errors[current_drive])
306#define FDCS (&fdc_state[fdc])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Joe Perches48c8cee2010-03-10 15:20:45 -0800308#define UDP (&drive_params[drive])
309#define UDRS (&drive_state[drive])
310#define UDRWE (&write_errors[drive])
311#define UFDCS (&fdc_state[FDC(drive)])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
Joe Perches48c8cee2010-03-10 15:20:45 -0800313#define PH_HEAD(floppy, head) (((((floppy)->stretch & 2) >> 1) ^ head) << 2)
314#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
315
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316/* read/write */
Joe Perches48c8cee2010-03-10 15:20:45 -0800317#define COMMAND (raw_cmd->cmd[0])
318#define DR_SELECT (raw_cmd->cmd[1])
319#define TRACK (raw_cmd->cmd[2])
320#define HEAD (raw_cmd->cmd[3])
321#define SECTOR (raw_cmd->cmd[4])
322#define SIZECODE (raw_cmd->cmd[5])
323#define SECT_PER_TRACK (raw_cmd->cmd[6])
324#define GAP (raw_cmd->cmd[7])
325#define SIZECODE2 (raw_cmd->cmd[8])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326#define NR_RW 9
327
328/* format */
Joe Perches48c8cee2010-03-10 15:20:45 -0800329#define F_SIZECODE (raw_cmd->cmd[2])
330#define F_SECT_PER_TRACK (raw_cmd->cmd[3])
331#define F_GAP (raw_cmd->cmd[4])
332#define F_FILL (raw_cmd->cmd[5])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333#define NR_F 6
334
335/*
Joe Perches48c8cee2010-03-10 15:20:45 -0800336 * Maximum disk size (in kilobytes).
337 * This default is used whenever the current disk size is unknown.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 * [Now it is rather a minimum]
339 */
340#define MAX_DISK_SIZE 4 /* 3984 */
341
342/*
343 * globals used by 'result()'
344 */
345#define MAX_REPLIES 16
346static unsigned char reply_buffer[MAX_REPLIES];
Joe Perches891eda82010-03-10 15:21:05 -0800347static int inr; /* size of reply buffer, when called from interrupt */
Joe Perches48c8cee2010-03-10 15:20:45 -0800348#define ST0 (reply_buffer[0])
349#define ST1 (reply_buffer[1])
350#define ST2 (reply_buffer[2])
351#define ST3 (reply_buffer[0]) /* result of GETSTATUS */
352#define R_TRACK (reply_buffer[3])
353#define R_HEAD (reply_buffer[4])
354#define R_SECTOR (reply_buffer[5])
355#define R_SIZECODE (reply_buffer[6])
356
357#define SEL_DLY (2 * HZ / 100)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
359/*
360 * this struct defines the different floppy drive types.
361 */
362static struct {
363 struct floppy_drive_params params;
364 const char *name; /* name printed while booting */
365} default_drive_params[] = {
366/* NOTE: the time values in jiffies should be in msec!
367 CMOS drive type
368 | Maximum data rate supported by drive type
369 | | Head load time, msec
370 | | | Head unload time, msec (not used)
371 | | | | Step rate interval, usec
372 | | | | | Time needed for spinup time (jiffies)
373 | | | | | | Timeout for spinning down (jiffies)
374 | | | | | | | Spindown offset (where disk stops)
375 | | | | | | | | Select delay
376 | | | | | | | | | RPS
377 | | | | | | | | | | Max number of tracks
378 | | | | | | | | | | | Interrupt timeout
379 | | | | | | | | | | | | Max nonintlv. sectors
380 | | | | | | | | | | | | | -Max Errors- flags */
381{{0, 500, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 80, 3*HZ, 20, {3,1,2,0,2}, 0,
382 0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },
383
384{{1, 300, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 40, 3*HZ, 17, {3,1,2,0,2}, 0,
385 0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
386
387{{2, 500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0,
388 0, { 2, 5, 6,23,10,20,12, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/
389
390{{3, 250, 16, 16, 3000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
391 0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/
392
393{{4, 500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
394 0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/
395
396{{5, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
397 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
398
399{{6, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
400 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*/
401/* | --autodetected formats--- | | |
402 * read_track | | Name printed when booting
403 * | Native format
404 * Frequency of disk change checks */
405};
406
407static struct floppy_drive_params drive_params[N_DRIVE];
408static struct floppy_drive_struct drive_state[N_DRIVE];
409static struct floppy_write_errors write_errors[N_DRIVE];
410static struct timer_list motor_off_timer[N_DRIVE];
411static struct gendisk *disks[N_DRIVE];
412static struct block_device *opened_bdev[N_DRIVE];
Jes Sorensenb1c82b52006-03-23 03:00:26 -0800413static DEFINE_MUTEX(open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
415
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
517#define NO_SIGNAL (!interruptible || !signal_pending(current))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
519/* Errors during formatting are counted here. */
520static int format_errors;
521
522/* Format request descriptor. */
523static struct format_descr format_req;
524
525/*
526 * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
527 * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
528 * H is head unload time (1=16ms, 2=32ms, etc)
529 */
530
531/*
532 * Track buffer
533 * Because these are written to by the DMA controller, they must
534 * not contain a 64k byte boundary crossing, or data will be
535 * corrupted/lost.
536 */
537static char *floppy_track_buffer;
538static int max_buffer_sectors;
539
540static int *errors;
Jesper Juhl06f748c2007-10-16 23:30:57 -0700541typedef void (*done_f)(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542static struct cont_t {
Joe Perches48c8cee2010-03-10 15:20:45 -0800543 void (*interrupt)(void);
544 /* this is called after the interrupt of the
545 * main command */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700546 void (*redo)(void); /* this is called to retry the operation */
547 void (*error)(void); /* this is called to tally an error */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 done_f done; /* this is called to say if the operation has
549 * succeeded/failed */
550} *cont;
551
552static void floppy_ready(void);
553static void floppy_start(void);
554static void process_fd_request(void);
555static void recalibrate_floppy(void);
556static void floppy_shutdown(unsigned long);
557
Philippe De Muyter5a74db02009-02-18 14:48:36 -0800558static int floppy_request_regions(int);
559static void floppy_release_regions(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560static int floppy_grab_irq_and_dma(void);
561static void floppy_release_irq_and_dma(void);
562
563/*
564 * The "reset" variable should be tested whenever an interrupt is scheduled,
565 * after the commands have been sent. This is to ensure that the driver doesn't
566 * get wedged when the interrupt doesn't come because of a failed command.
567 * reset doesn't need to be tested before sending commands, because
568 * output_byte is automatically disabled when reset is set.
569 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570static void reset_fdc(void);
571
572/*
573 * These are global variables, as that's the easiest way to give
574 * information to interrupts. They are the data used for the current
575 * request.
576 */
Joe Perches48c8cee2010-03-10 15:20:45 -0800577#define NO_TRACK -1
578#define NEED_1_RECAL -2
579#define NEED_2_RECAL -3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
581static int usage_count;
582
583/* buffer related variables */
584static int buffer_track = -1;
585static int buffer_drive = -1;
586static int buffer_min = -1;
587static int buffer_max = -1;
588
589/* fdc related variables, should end up in a struct */
590static struct floppy_fdc_state fdc_state[N_FDC];
591static int fdc; /* current fdc */
592
593static struct floppy_struct *_floppy = floppy_type;
594static unsigned char current_drive;
595static long current_count_sectors;
596static unsigned char fsector_t; /* sector in track */
597static unsigned char in_sector_offset; /* offset within physical sector,
598 * expressed in units of 512 bytes */
599
600#ifndef fd_eject
601static inline int fd_eject(int drive)
602{
603 return -EINVAL;
604}
605#endif
606
607/*
608 * Debugging
609 * =========
610 */
611#ifdef DEBUGT
612static long unsigned debugtimer;
613
614static inline void set_debugt(void)
615{
616 debugtimer = jiffies;
617}
618
Joe Perchesded28632010-03-10 15:21:09 -0800619static inline void debugt(const char *func, const char *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620{
621 if (DP->flags & DEBUGT)
Joe Perchesded28632010-03-10 15:21:09 -0800622 pr_info("%s:%s dtime=%lu\n", func, msg, jiffies - debugtimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623}
624#else
625static inline void set_debugt(void) { }
Joe Perchesded28632010-03-10 15:21:09 -0800626static inline void debugt(const char *func, const char *msg) { }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627#endif /* DEBUGT */
628
Joe Perchesa0a52d62010-03-10 15:20:52 -0800629typedef void (*timeout_fn)(unsigned long);
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700630static DEFINE_TIMER(fd_timeout, floppy_shutdown, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
632static const char *timeout_message;
633
Joe Perches275176b2010-03-10 15:21:06 -0800634static void is_alive(const char *func, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635{
636 /* this routine checks whether the floppy driver is "alive" */
Joe Perchesc5297302010-03-10 15:20:58 -0800637 if (test_bit(0, &fdc_busy) && command_status < 2 &&
638 !timer_pending(&fd_timeout)) {
Joe Perches275176b2010-03-10 15:21:06 -0800639 DPRINT("%s: timeout handler died. %s\n", func, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 }
641}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
Joe Perches48c8cee2010-03-10 15:20:45 -0800643static void (*do_floppy)(void) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645#define OLOGSIZE 20
646
Joe Perches48c8cee2010-03-10 15:20:45 -0800647static void (*lasthandler)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648static unsigned long interruptjiffies;
649static unsigned long resultjiffies;
650static int resultsize;
651static unsigned long lastredo;
652
653static struct output_log {
654 unsigned char data;
655 unsigned char status;
656 unsigned long jiffies;
657} output_log[OLOGSIZE];
658
659static int output_log_pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
661#define current_reqD -1
662#define MAXTIMEOUT -2
663
Joe Perches73507e62010-03-10 15:21:03 -0800664static void __reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665{
666 if (drive == current_reqD)
667 drive = current_drive;
668 del_timer(&fd_timeout);
Eric Sesterhenn / Snakebyte4acb3e22007-05-23 13:58:15 -0700669 if (drive < 0 || drive >= N_DRIVE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 fd_timeout.expires = jiffies + 20UL * HZ;
671 drive = 0;
672 } else
673 fd_timeout.expires = jiffies + UDP->timeout;
674 add_timer(&fd_timeout);
Joe Perchesa81ee542010-03-10 15:20:46 -0800675 if (UDP->flags & FD_DEBUG)
Joe Perches73507e62010-03-10 15:21:03 -0800676 DPRINT("reschedule timeout %s\n", message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 timeout_message = message;
678}
679
Joe Perches73507e62010-03-10 15:21:03 -0800680static void reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681{
682 unsigned long flags;
683
684 spin_lock_irqsave(&floppy_lock, flags);
Joe Perches73507e62010-03-10 15:21:03 -0800685 __reschedule_timeout(drive, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 spin_unlock_irqrestore(&floppy_lock, flags);
687}
688
Joe Perches48c8cee2010-03-10 15:20:45 -0800689#define INFBOUND(a, b) (a) = max_t(int, a, b)
690#define SUPBOUND(a, b) (a) = min_t(int, a, b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
692/*
693 * Bottom half floppy driver.
694 * ==========================
695 *
696 * This part of the file contains the code talking directly to the hardware,
697 * and also the main service loop (seek-configure-spinup-command)
698 */
699
700/*
701 * disk change.
702 * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
703 * and the last_checked date.
704 *
705 * last_checked is the date of the last check which showed 'no disk change'
706 * FD_DISK_CHANGE is set under two conditions:
707 * 1. The floppy has been changed after some i/o to that floppy already
708 * took place.
709 * 2. No floppy disk is in the drive. This is done in order to ensure that
710 * requests are quickly flushed in case there is no disk in the drive. It
711 * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
712 * the drive.
713 *
714 * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
715 * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
716 * each seek. If a disk is present, the disk change line should also be
717 * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
718 * change line is set, this means either that no disk is in the drive, or
719 * that it has been removed since the last seek.
720 *
721 * This means that we really have a third possibility too:
722 * The floppy has been changed after the last seek.
723 */
724
725static int disk_change(int drive)
726{
727 int fdc = FDC(drive);
Jesper Juhl06f748c2007-10-16 23:30:57 -0700728
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800729 if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 DPRINT("WARNING disk change called early\n");
731 if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
732 (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
733 DPRINT("probing disk change on unselected drive\n");
734 DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
735 (unsigned int)FDCS->dor);
736 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
Joe Perches87f530d2010-03-10 15:20:54 -0800738 debug_dcl(UDP->flags,
739 "checking disk change line for drive %d\n", drive);
740 debug_dcl(UDP->flags, "jiffies=%lu\n", jiffies);
741 debug_dcl(UDP->flags, "disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
742 debug_dcl(UDP->flags, "flags=%lx\n", UDRS->flags);
743
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 if (UDP->flags & FD_BROKEN_DCL)
Joe Perchese0298532010-03-10 15:20:55 -0800745 return test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
Joe Perchese0298532010-03-10 15:20:55 -0800747 set_bit(FD_VERIFY_BIT, &UDRS->flags);
748 /* verify write protection */
749
750 if (UDRS->maxblock) /* mark it changed */
751 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
753 /* invalidate its geometry */
754 if (UDRS->keep_data >= 0) {
755 if ((UDP->flags & FTD_MSG) &&
756 current_type[drive] != NULL)
Joe Perches891eda82010-03-10 15:21:05 -0800757 DPRINT("Disk type is undefined after disk change\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 current_type[drive] = NULL;
759 floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
760 }
761
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 return 1;
763 } else {
764 UDRS->last_checked = jiffies;
Joe Perchese0298532010-03-10 15:20:55 -0800765 clear_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 }
767 return 0;
768}
769
770static inline int is_selected(int dor, int unit)
771{
772 return ((dor & (0x10 << unit)) && (dor & 3) == unit);
773}
774
Joe Perches57584c52010-03-10 15:21:00 -0800775static bool is_ready_state(int status)
776{
777 int state = status & (STATUS_READY | STATUS_DIR | STATUS_DMA);
778 return state == STATUS_READY;
779}
780
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781static int set_dor(int fdc, char mask, char data)
782{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700783 unsigned char unit;
784 unsigned char drive;
785 unsigned char newdor;
786 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
788 if (FDCS->address == -1)
789 return -1;
790
791 olddor = FDCS->dor;
792 newdor = (olddor & mask) | data;
793 if (newdor != olddor) {
794 unit = olddor & 0x3;
795 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
796 drive = REVDRIVE(fdc, unit);
Joe Perches87f530d2010-03-10 15:20:54 -0800797 debug_dcl(UDP->flags,
798 "calling disk change from set_dor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 disk_change(drive);
800 }
801 FDCS->dor = newdor;
802 fd_outb(newdor, FD_DOR);
803
804 unit = newdor & 0x3;
805 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
806 drive = REVDRIVE(fdc, unit);
807 UDRS->select_date = jiffies;
808 }
809 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 return olddor;
811}
812
813static void twaddle(void)
814{
815 if (DP->select_delay)
816 return;
817 fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
818 fd_outb(FDCS->dor, FD_DOR);
819 DRS->select_date = jiffies;
820}
821
Joe Perches57584c52010-03-10 15:21:00 -0800822/*
823 * Reset all driver information about the current fdc.
824 * This is needed after a reset, and after a raw command.
825 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826static void reset_fdc_info(int mode)
827{
828 int drive;
829
830 FDCS->spec1 = FDCS->spec2 = -1;
831 FDCS->need_configure = 1;
832 FDCS->perp_mode = 1;
833 FDCS->rawcmd = 0;
834 for (drive = 0; drive < N_DRIVE; drive++)
835 if (FDC(drive) == fdc && (mode || UDRS->track != NEED_1_RECAL))
836 UDRS->track = NEED_2_RECAL;
837}
838
839/* selects the fdc and drive, and enables the fdc's input/dma. */
840static void set_fdc(int drive)
841{
842 if (drive >= 0 && drive < N_DRIVE) {
843 fdc = FDC(drive);
844 current_drive = drive;
845 }
846 if (fdc != 1 && fdc != 0) {
Joe Perchesb46df352010-03-10 15:20:46 -0800847 pr_info("bad fdc value\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 return;
849 }
850 set_dor(fdc, ~0, 8);
851#if N_FDC > 1
852 set_dor(1 - fdc, ~8, 0);
853#endif
854 if (FDCS->rawcmd == 2)
855 reset_fdc_info(1);
856 if (fd_inb(FD_STATUS) != STATUS_READY)
857 FDCS->reset = 1;
858}
859
860/* locks the driver */
Joe Perches74f63f42010-03-10 15:20:58 -0800861static int _lock_fdc(int drive, bool interruptible, int line)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862{
863 if (!usage_count) {
Joe Perchesb46df352010-03-10 15:20:46 -0800864 pr_err("Trying to lock fdc while usage count=0 at line %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 line);
866 return -1;
867 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868
869 if (test_and_set_bit(0, &fdc_busy)) {
870 DECLARE_WAITQUEUE(wait, current);
871 add_wait_queue(&fdc_wait, &wait);
872
873 for (;;) {
874 set_current_state(TASK_INTERRUPTIBLE);
875
876 if (!test_and_set_bit(0, &fdc_busy))
877 break;
878
879 schedule();
880
881 if (!NO_SIGNAL) {
882 remove_wait_queue(&fdc_wait, &wait);
883 return -EINTR;
884 }
885 }
886
887 set_current_state(TASK_RUNNING);
888 remove_wait_queue(&fdc_wait, &wait);
Ingo Molnar3e541a42006-07-03 00:24:23 -0700889 flush_scheduled_work();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 }
891 command_status = FD_COMMAND_NONE;
892
Joe Perches73507e62010-03-10 15:21:03 -0800893 __reschedule_timeout(drive, "lock fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 set_fdc(drive);
895 return 0;
896}
897
Joe Perches48c8cee2010-03-10 15:20:45 -0800898#define lock_fdc(drive, interruptible) \
899 _lock_fdc(drive, interruptible, __LINE__)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901/* unlocks the driver */
902static inline void unlock_fdc(void)
903{
904 unsigned long flags;
905
906 raw_cmd = NULL;
907 if (!test_bit(0, &fdc_busy))
908 DPRINT("FDC access conflict!\n");
909
910 if (do_floppy)
Joe Perches1ebddd82010-03-10 15:21:07 -0800911 DPRINT("device interrupt still active at FDC release: %pf!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 do_floppy);
913 command_status = FD_COMMAND_NONE;
914 spin_lock_irqsave(&floppy_lock, flags);
915 del_timer(&fd_timeout);
916 cont = NULL;
917 clear_bit(0, &fdc_busy);
Tejun Heo9934c8c2009-05-08 11:54:16 +0900918 if (current_req || blk_peek_request(floppy_queue))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 do_fd_request(floppy_queue);
920 spin_unlock_irqrestore(&floppy_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 wake_up(&fdc_wait);
922}
923
924/* switches the motor off after a given timeout */
925static void motor_off_callback(unsigned long nr)
926{
927 unsigned char mask = ~(0x10 << UNIT(nr));
928
929 set_dor(FDC(nr), mask, 0);
930}
931
932/* schedules motor off */
933static void floppy_off(unsigned int drive)
934{
935 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700936 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937
938 if (!(FDCS->dor & (0x10 << UNIT(drive))))
939 return;
940
941 del_timer(motor_off_timer + drive);
942
943 /* make spindle stop in a position which minimizes spinup time
944 * next time */
945 if (UDP->rps) {
946 delta = jiffies - UDRS->first_read_date + HZ -
947 UDP->spindown_offset;
948 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
949 motor_off_timer[drive].expires =
950 jiffies + UDP->spindown - delta;
951 }
952 add_timer(motor_off_timer + drive);
953}
954
955/*
956 * cycle through all N_DRIVE floppy drives, for disk change testing.
957 * stopping at current drive. This is done before any long operation, to
958 * be sure to have up to date disk change information.
959 */
960static void scandrives(void)
961{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700962 int i;
963 int drive;
964 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
966 if (DP->select_delay)
967 return;
968
969 saved_drive = current_drive;
970 for (i = 0; i < N_DRIVE; i++) {
971 drive = (saved_drive + i + 1) % N_DRIVE;
972 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
973 continue; /* skip closed drives */
974 set_fdc(drive);
975 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
976 (0x10 << UNIT(drive))))
977 /* switch the motor off again, if it was off to
978 * begin with */
979 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
980 }
981 set_fdc(saved_drive);
982}
983
984static void empty(void)
985{
986}
987
David Howells65f27f32006-11-22 14:55:48 +0000988static DECLARE_WORK(floppy_work, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
Joe Perches48c8cee2010-03-10 15:20:45 -0800990static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991{
David Howells65f27f32006-11-22 14:55:48 +0000992 PREPARE_WORK(&floppy_work, (work_func_t)handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 schedule_work(&floppy_work);
994}
995
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700996static DEFINE_TIMER(fd_timer, NULL, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
998static void cancel_activity(void)
999{
1000 unsigned long flags;
1001
1002 spin_lock_irqsave(&floppy_lock, flags);
1003 do_floppy = NULL;
David Howells65f27f32006-11-22 14:55:48 +00001004 PREPARE_WORK(&floppy_work, (work_func_t)empty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 del_timer(&fd_timer);
1006 spin_unlock_irqrestore(&floppy_lock, flags);
1007}
1008
1009/* this function makes sure that the disk stays in the drive during the
1010 * transfer */
1011static void fd_watchdog(void)
1012{
Joe Perches87f530d2010-03-10 15:20:54 -08001013 debug_dcl(DP->flags, "calling disk change from watchdog\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014
1015 if (disk_change(current_drive)) {
1016 DPRINT("disk removed during i/o\n");
1017 cancel_activity();
1018 cont->done(0);
1019 reset_fdc();
1020 } else {
1021 del_timer(&fd_timer);
Joe Perchesa0a52d62010-03-10 15:20:52 -08001022 fd_timer.function = (timeout_fn)fd_watchdog;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 fd_timer.expires = jiffies + HZ / 10;
1024 add_timer(&fd_timer);
1025 }
1026}
1027
1028static void main_command_interrupt(void)
1029{
1030 del_timer(&fd_timer);
1031 cont->interrupt();
1032}
1033
1034/* waits for a delay (spinup or select) to pass */
1035static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
1036{
1037 if (FDCS->reset) {
1038 reset_fdc(); /* do the reset during sleep to win time
1039 * if we don't need to sleep, it's a good
1040 * occasion anyways */
1041 return 1;
1042 }
1043
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001044 if (time_before(jiffies, delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 del_timer(&fd_timer);
1046 fd_timer.function = function;
1047 fd_timer.expires = delay;
1048 add_timer(&fd_timer);
1049 return 1;
1050 }
1051 return 0;
1052}
1053
1054static DEFINE_SPINLOCK(floppy_hlt_lock);
1055static int hlt_disabled;
1056static void floppy_disable_hlt(void)
1057{
1058 unsigned long flags;
1059
1060 spin_lock_irqsave(&floppy_hlt_lock, flags);
1061 if (!hlt_disabled) {
1062 hlt_disabled = 1;
1063#ifdef HAVE_DISABLE_HLT
1064 disable_hlt();
1065#endif
1066 }
1067 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1068}
1069
1070static void floppy_enable_hlt(void)
1071{
1072 unsigned long flags;
1073
1074 spin_lock_irqsave(&floppy_hlt_lock, flags);
1075 if (hlt_disabled) {
1076 hlt_disabled = 0;
1077#ifdef HAVE_DISABLE_HLT
1078 enable_hlt();
1079#endif
1080 }
1081 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1082}
1083
1084static void setup_DMA(void)
1085{
1086 unsigned long f;
1087
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 if (raw_cmd->length == 0) {
1089 int i;
1090
Joe Perchesb46df352010-03-10 15:20:46 -08001091 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001093 pr_cont("%x,", raw_cmd->cmd[i]);
1094 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 cont->done(0);
1096 FDCS->reset = 1;
1097 return;
1098 }
1099 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001100 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 cont->done(0);
1102 FDCS->reset = 1;
1103 return;
1104 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 f = claim_dma_lock();
1106 fd_disable_dma();
1107#ifdef fd_dma_setup
1108 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1109 (raw_cmd->flags & FD_RAW_READ) ?
1110 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1111 release_dma_lock(f);
1112 cont->done(0);
1113 FDCS->reset = 1;
1114 return;
1115 }
1116 release_dma_lock(f);
1117#else
1118 fd_clear_dma_ff();
1119 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1120 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1121 DMA_MODE_READ : DMA_MODE_WRITE);
1122 fd_set_dma_addr(raw_cmd->kernel_data);
1123 fd_set_dma_count(raw_cmd->length);
1124 virtual_dma_port = FDCS->address;
1125 fd_enable_dma();
1126 release_dma_lock(f);
1127#endif
1128 floppy_disable_hlt();
1129}
1130
1131static void show_floppy(void);
1132
1133/* waits until the fdc becomes ready */
1134static int wait_til_ready(void)
1135{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001136 int status;
1137 int counter;
1138
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 if (FDCS->reset)
1140 return -1;
1141 for (counter = 0; counter < 10000; counter++) {
1142 status = fd_inb(FD_STATUS);
1143 if (status & STATUS_READY)
1144 return status;
1145 }
Joe Perches29f1c782010-03-10 15:21:00 -08001146 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1148 show_floppy();
1149 }
1150 FDCS->reset = 1;
1151 return -1;
1152}
1153
1154/* sends a command byte to the fdc */
1155static int output_byte(char byte)
1156{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001157 int status = wait_til_ready();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001159 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001161
1162 if (is_ready_state(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 fd_outb(byte, FD_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 output_log[output_log_pos].data = byte;
1165 output_log[output_log_pos].status = status;
1166 output_log[output_log_pos].jiffies = jiffies;
1167 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 return 0;
1169 }
1170 FDCS->reset = 1;
Joe Perches29f1c782010-03-10 15:21:00 -08001171 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1173 byte, fdc, status);
1174 show_floppy();
1175 }
1176 return -1;
1177}
1178
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179/* gets the response from the fdc */
1180static int result(void)
1181{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001182 int i;
1183 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184
1185 for (i = 0; i < MAX_REPLIES; i++) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001186 status = wait_til_ready();
1187 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 break;
1189 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1190 if ((status & ~STATUS_BUSY) == STATUS_READY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 resultjiffies = jiffies;
1192 resultsize = i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 return i;
1194 }
1195 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1196 reply_buffer[i] = fd_inb(FD_DATA);
1197 else
1198 break;
1199 }
Joe Perches29f1c782010-03-10 15:21:00 -08001200 if (initialized) {
1201 DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1202 fdc, status, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 show_floppy();
1204 }
1205 FDCS->reset = 1;
1206 return -1;
1207}
1208
1209#define MORE_OUTPUT -2
1210/* does the fdc need more output? */
1211static int need_more_output(void)
1212{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001213 int status = wait_til_ready();
Jesper Juhl06f748c2007-10-16 23:30:57 -07001214
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001215 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001217
1218 if (is_ready_state(status))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 return MORE_OUTPUT;
Joe Perches57584c52010-03-10 15:21:00 -08001220
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 return result();
1222}
1223
1224/* Set perpendicular mode as required, based on data rate, if supported.
1225 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1226 */
1227static inline void perpendicular_mode(void)
1228{
1229 unsigned char perp_mode;
1230
1231 if (raw_cmd->rate & 0x40) {
1232 switch (raw_cmd->rate & 3) {
1233 case 0:
1234 perp_mode = 2;
1235 break;
1236 case 3:
1237 perp_mode = 3;
1238 break;
1239 default:
1240 DPRINT("Invalid data rate for perpendicular mode!\n");
1241 cont->done(0);
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001242 FDCS->reset = 1;
1243 /*
1244 * convenient way to return to
1245 * redo without too much hassle
1246 * (deep stack et al.)
1247 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 return;
1249 }
1250 } else
1251 perp_mode = 0;
1252
1253 if (FDCS->perp_mode == perp_mode)
1254 return;
1255 if (FDCS->version >= FDC_82077_ORIG) {
1256 output_byte(FD_PERPENDICULAR);
1257 output_byte(perp_mode);
1258 FDCS->perp_mode = perp_mode;
1259 } else if (perp_mode) {
1260 DPRINT("perpendicular mode not supported by this FDC.\n");
1261 }
1262} /* perpendicular_mode */
1263
1264static int fifo_depth = 0xa;
1265static int no_fifo;
1266
1267static int fdc_configure(void)
1268{
1269 /* Turn on FIFO */
1270 output_byte(FD_CONFIGURE);
1271 if (need_more_output() != MORE_OUTPUT)
1272 return 0;
1273 output_byte(0);
1274 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1275 output_byte(0); /* pre-compensation from track
1276 0 upwards */
1277 return 1;
1278}
1279
1280#define NOMINAL_DTR 500
1281
1282/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1283 * head load time, and DMA disable flag to values needed by floppy.
1284 *
1285 * The value "dtr" is the data transfer rate in Kbps. It is needed
1286 * to account for the data rate-based scaling done by the 82072 and 82077
1287 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1288 * 8272a).
1289 *
1290 * Note that changing the data transfer rate has a (probably deleterious)
1291 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1292 * fdc_specify is called again after each data transfer rate
1293 * change.
1294 *
1295 * srt: 1000 to 16000 in microseconds
1296 * hut: 16 to 240 milliseconds
1297 * hlt: 2 to 254 milliseconds
1298 *
1299 * These values are rounded up to the next highest available delay time.
1300 */
1301static void fdc_specify(void)
1302{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001303 unsigned char spec1;
1304 unsigned char spec2;
1305 unsigned long srt;
1306 unsigned long hlt;
1307 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 unsigned long dtr = NOMINAL_DTR;
1309 unsigned long scale_dtr = NOMINAL_DTR;
1310 int hlt_max_code = 0x7f;
1311 int hut_max_code = 0xf;
1312
1313 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1314 fdc_configure();
1315 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 }
1317
1318 switch (raw_cmd->rate & 0x03) {
1319 case 3:
1320 dtr = 1000;
1321 break;
1322 case 1:
1323 dtr = 300;
1324 if (FDCS->version >= FDC_82078) {
1325 /* chose the default rate table, not the one
1326 * where 1 = 2 Mbps */
1327 output_byte(FD_DRIVESPEC);
1328 if (need_more_output() == MORE_OUTPUT) {
1329 output_byte(UNIT(current_drive));
1330 output_byte(0xc0);
1331 }
1332 }
1333 break;
1334 case 2:
1335 dtr = 250;
1336 break;
1337 }
1338
1339 if (FDCS->version >= FDC_82072) {
1340 scale_dtr = dtr;
1341 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1342 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1343 }
1344
1345 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001346 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001347 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001349
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 SUPBOUND(srt, 0xf);
1351 INFBOUND(srt, 0);
1352
Julia Lawall061837b2008-09-22 14:57:16 -07001353 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 if (hlt < 0x01)
1355 hlt = 0x01;
1356 else if (hlt > 0x7f)
1357 hlt = hlt_max_code;
1358
Julia Lawall061837b2008-09-22 14:57:16 -07001359 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 if (hut < 0x1)
1361 hut = 0x1;
1362 else if (hut > 0xf)
1363 hut = hut_max_code;
1364
1365 spec1 = (srt << 4) | hut;
1366 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1367
1368 /* If these parameters did not change, just return with success */
1369 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1370 /* Go ahead and set spec1 and spec2 */
1371 output_byte(FD_SPECIFY);
1372 output_byte(FDCS->spec1 = spec1);
1373 output_byte(FDCS->spec2 = spec2);
1374 }
1375} /* fdc_specify */
1376
1377/* Set the FDC's data transfer rate on behalf of the specified drive.
1378 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1379 * of the specify command (i.e. using the fdc_specify function).
1380 */
1381static int fdc_dtr(void)
1382{
1383 /* If data rate not already set to desired value, set it. */
1384 if ((raw_cmd->rate & 3) == FDCS->dtr)
1385 return 0;
1386
1387 /* Set dtr */
1388 fd_outb(raw_cmd->rate & 3, FD_DCR);
1389
1390 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1391 * need a stabilization period of several milliseconds to be
1392 * enforced after data rate changes before R/W operations.
1393 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1394 */
1395 FDCS->dtr = raw_cmd->rate & 3;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001396 return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
1397 (timeout_fn)floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398} /* fdc_dtr */
1399
1400static void tell_sector(void)
1401{
Joe Perchesb46df352010-03-10 15:20:46 -08001402 pr_cont(": track %d, head %d, sector %d, size %d",
1403 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404} /* tell_sector */
1405
Joe Perchesb46df352010-03-10 15:20:46 -08001406static void print_errors(void)
1407{
1408 DPRINT("");
1409 if (ST0 & ST0_ECE) {
1410 pr_cont("Recalibrate failed!");
1411 } else if (ST2 & ST2_CRC) {
1412 pr_cont("data CRC error");
1413 tell_sector();
1414 } else if (ST1 & ST1_CRC) {
1415 pr_cont("CRC error");
1416 tell_sector();
1417 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1418 (ST2 & ST2_MAM)) {
1419 if (!probing) {
1420 pr_cont("sector not found");
1421 tell_sector();
1422 } else
1423 pr_cont("probe failed...");
1424 } else if (ST2 & ST2_WC) { /* seek error */
1425 pr_cont("wrong cylinder");
1426 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1427 pr_cont("bad cylinder");
1428 } else {
1429 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1430 ST0, ST1, ST2);
1431 tell_sector();
1432 }
1433 pr_cont("\n");
1434}
1435
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436/*
1437 * OK, this error interpreting routine is called after a
1438 * DMA read/write has succeeded
1439 * or failed, so we check the results, and copy any buffers.
1440 * hhb: Added better error reporting.
1441 * ak: Made this into a separate routine.
1442 */
1443static int interpret_errors(void)
1444{
1445 char bad;
1446
1447 if (inr != 7) {
Joe Perches891eda82010-03-10 15:21:05 -08001448 DPRINT("-- FDC reply error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 FDCS->reset = 1;
1450 return 1;
1451 }
1452
1453 /* check IC to find cause of interrupt */
1454 switch (ST0 & ST0_INTR) {
1455 case 0x40: /* error occurred during command execution */
1456 if (ST1 & ST1_EOC)
1457 return 0; /* occurs with pseudo-DMA */
1458 bad = 1;
1459 if (ST1 & ST1_WP) {
1460 DPRINT("Drive is write protected\n");
Joe Perchese0298532010-03-10 15:20:55 -08001461 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 cont->done(0);
1463 bad = 2;
1464 } else if (ST1 & ST1_ND) {
Joe Perchese0298532010-03-10 15:20:55 -08001465 set_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 } else if (ST1 & ST1_OR) {
1467 if (DP->flags & FTD_MSG)
1468 DPRINT("Over/Underrun - retrying\n");
1469 bad = 0;
1470 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001471 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 }
1473 if (ST2 & ST2_WC || ST2 & ST2_BC)
1474 /* wrong cylinder => recal */
1475 DRS->track = NEED_2_RECAL;
1476 return bad;
1477 case 0x80: /* invalid command given */
1478 DPRINT("Invalid FDC command given!\n");
1479 cont->done(0);
1480 return 2;
1481 case 0xc0:
1482 DPRINT("Abnormal termination caused by polling\n");
1483 cont->error();
1484 return 2;
1485 default: /* (0) Normal command termination */
1486 return 0;
1487 }
1488}
1489
1490/*
1491 * This routine is called when everything should be correctly set up
1492 * for the transfer (i.e. floppy motor is on, the correct floppy is
1493 * selected, and the head is sitting on the right track).
1494 */
1495static void setup_rw_floppy(void)
1496{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001497 int i;
1498 int r;
1499 int flags;
1500 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 unsigned long ready_date;
1502 timeout_fn function;
1503
1504 flags = raw_cmd->flags;
1505 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1506 flags |= FD_RAW_INTR;
1507
1508 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1509 ready_date = DRS->spinup_date + DP->spinup;
1510 /* If spinup will take a long time, rerun scandrives
1511 * again just before spinup completion. Beware that
1512 * after scandrives, we must again wait for selection.
1513 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001514 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 ready_date -= DP->select_delay;
Joe Perchesa0a52d62010-03-10 15:20:52 -08001516 function = (timeout_fn)floppy_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 } else
Joe Perchesa0a52d62010-03-10 15:20:52 -08001518 function = (timeout_fn)setup_rw_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519
1520 /* wait until the floppy is spinning fast enough */
1521 if (fd_wait_for_completion(ready_date, function))
1522 return;
1523 }
1524 dflags = DRS->flags;
1525
1526 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1527 setup_DMA();
1528
1529 if (flags & FD_RAW_INTR)
1530 do_floppy = main_command_interrupt;
1531
1532 r = 0;
1533 for (i = 0; i < raw_cmd->cmd_count; i++)
1534 r |= output_byte(raw_cmd->cmd[i]);
1535
Joe Perchesded28632010-03-10 15:21:09 -08001536 debugt(__func__, "rw_command");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537
1538 if (r) {
1539 cont->error();
1540 reset_fdc();
1541 return;
1542 }
1543
1544 if (!(flags & FD_RAW_INTR)) {
1545 inr = result();
1546 cont->interrupt();
1547 } else if (flags & FD_RAW_NEED_DISK)
1548 fd_watchdog();
1549}
1550
1551static int blind_seek;
1552
1553/*
1554 * This is the routine called after every seek (or recalibrate) interrupt
1555 * from the floppy controller.
1556 */
1557static void seek_interrupt(void)
1558{
Joe Perchesded28632010-03-10 15:21:09 -08001559 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1561 DPRINT("seek failed\n");
1562 DRS->track = NEED_2_RECAL;
1563 cont->error();
1564 cont->redo();
1565 return;
1566 }
1567 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
Joe Perches87f530d2010-03-10 15:20:54 -08001568 debug_dcl(DP->flags,
1569 "clearing NEWCHANGE flag because of effective seek\n");
1570 debug_dcl(DP->flags, "jiffies=%lu\n", jiffies);
Joe Perchese0298532010-03-10 15:20:55 -08001571 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
1572 /* effective seek */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 DRS->select_date = jiffies;
1574 }
1575 DRS->track = ST1;
1576 floppy_ready();
1577}
1578
1579static void check_wp(void)
1580{
Joe Perchese0298532010-03-10 15:20:55 -08001581 if (test_bit(FD_VERIFY_BIT, &DRS->flags)) {
1582 /* check write protection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 output_byte(FD_GETSTATUS);
1584 output_byte(UNIT(current_drive));
1585 if (result() != 1) {
1586 FDCS->reset = 1;
1587 return;
1588 }
Joe Perchese0298532010-03-10 15:20:55 -08001589 clear_bit(FD_VERIFY_BIT, &DRS->flags);
1590 clear_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Joe Perches87f530d2010-03-10 15:20:54 -08001591 debug_dcl(DP->flags,
1592 "checking whether disk is write protected\n");
1593 debug_dcl(DP->flags, "wp=%x\n", ST3 & 0x40);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 if (!(ST3 & 0x40))
Joe Perchese0298532010-03-10 15:20:55 -08001595 set_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 else
Joe Perchese0298532010-03-10 15:20:55 -08001597 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 }
1599}
1600
1601static void seek_floppy(void)
1602{
1603 int track;
1604
1605 blind_seek = 0;
1606
Joe Perchesded28632010-03-10 15:21:09 -08001607 debug_dcl(DP->flags, "calling disk change from %s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608
Joe Perchese0298532010-03-10 15:20:55 -08001609 if (!test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1611 /* the media changed flag should be cleared after the seek.
1612 * If it isn't, this means that there is really no disk in
1613 * the drive.
1614 */
Joe Perchese0298532010-03-10 15:20:55 -08001615 set_bit(FD_DISK_CHANGED_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 cont->done(0);
1617 cont->redo();
1618 return;
1619 }
1620 if (DRS->track <= NEED_1_RECAL) {
1621 recalibrate_floppy();
1622 return;
Joe Perchese0298532010-03-10 15:20:55 -08001623 } else if (test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1625 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1626 /* we seek to clear the media-changed condition. Does anybody
1627 * know a more elegant way, which works on all drives? */
1628 if (raw_cmd->track)
1629 track = raw_cmd->track - 1;
1630 else {
1631 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1632 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1633 blind_seek = 1;
1634 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1635 }
1636 track = 1;
1637 }
1638 } else {
1639 check_wp();
1640 if (raw_cmd->track != DRS->track &&
1641 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1642 track = raw_cmd->track;
1643 else {
1644 setup_rw_floppy();
1645 return;
1646 }
1647 }
1648
1649 do_floppy = seek_interrupt;
1650 output_byte(FD_SEEK);
1651 output_byte(UNIT(current_drive));
Joe Perches2300f902010-03-10 15:20:49 -08001652 if (output_byte(track) < 0) {
1653 reset_fdc();
1654 return;
1655 }
Joe Perchesded28632010-03-10 15:21:09 -08001656 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657}
1658
1659static void recal_interrupt(void)
1660{
Joe Perchesded28632010-03-10 15:21:09 -08001661 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 if (inr != 2)
1663 FDCS->reset = 1;
1664 else if (ST0 & ST0_ECE) {
1665 switch (DRS->track) {
1666 case NEED_1_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001667 debugt(__func__, "need 1 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 /* after a second recalibrate, we still haven't
1669 * reached track 0. Probably no drive. Raise an
1670 * error, as failing immediately might upset
1671 * computers possessed by the Devil :-) */
1672 cont->error();
1673 cont->redo();
1674 return;
1675 case NEED_2_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001676 debugt(__func__, "need 2 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 /* If we already did a recalibrate,
1678 * and we are not at track 0, this
1679 * means we have moved. (The only way
1680 * not to move at recalibration is to
1681 * be already at track 0.) Clear the
1682 * new change flag */
Joe Perches87f530d2010-03-10 15:20:54 -08001683 debug_dcl(DP->flags,
1684 "clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685
Joe Perchese0298532010-03-10 15:20:55 -08001686 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 DRS->select_date = jiffies;
1688 /* fall through */
1689 default:
Joe Perchesded28632010-03-10 15:21:09 -08001690 debugt(__func__, "default");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 /* Recalibrate moves the head by at
1692 * most 80 steps. If after one
1693 * recalibrate we don't have reached
1694 * track 0, this might mean that we
1695 * started beyond track 80. Try
1696 * again. */
1697 DRS->track = NEED_1_RECAL;
1698 break;
1699 }
1700 } else
1701 DRS->track = ST1;
1702 floppy_ready();
1703}
1704
1705static void print_result(char *message, int inr)
1706{
1707 int i;
1708
1709 DPRINT("%s ", message);
1710 if (inr >= 0)
1711 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001712 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1713 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714}
1715
1716/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001717irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 int do_print;
1720 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001721 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722
1723 lasthandler = handler;
1724 interruptjiffies = jiffies;
1725
1726 f = claim_dma_lock();
1727 fd_disable_dma();
1728 release_dma_lock(f);
1729
1730 floppy_enable_hlt();
1731 do_floppy = NULL;
1732 if (fdc >= N_FDC || FDCS->address == -1) {
1733 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001734 pr_info("DOR0=%x\n", fdc_state[0].dor);
1735 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
Joe Perches1ebddd82010-03-10 15:21:07 -08001736 pr_info("handler=%pf\n", handler);
Joe Perches275176b2010-03-10 15:21:06 -08001737 is_alive(__func__, "bizarre fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 return IRQ_NONE;
1739 }
1740
1741 FDCS->reset = 0;
1742 /* We have to clear the reset flag here, because apparently on boxes
1743 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1744 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1745 * emission of the SENSEI's.
1746 * It is OK to emit floppy commands because we are in an interrupt
1747 * handler here, and thus we have to fear no interference of other
1748 * activity.
1749 */
1750
Joe Perches29f1c782010-03-10 15:21:00 -08001751 do_print = !handler && print_unex && initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752
1753 inr = result();
1754 if (do_print)
1755 print_result("unexpected interrupt", inr);
1756 if (inr == 0) {
1757 int max_sensei = 4;
1758 do {
1759 output_byte(FD_SENSEI);
1760 inr = result();
1761 if (do_print)
1762 print_result("sensei", inr);
1763 max_sensei--;
Joe Perchesc5297302010-03-10 15:20:58 -08001764 } while ((ST0 & 0x83) != UNIT(current_drive) &&
1765 inr == 2 && max_sensei);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 }
1767 if (!handler) {
1768 FDCS->reset = 1;
1769 return IRQ_NONE;
1770 }
1771 schedule_bh(handler);
Joe Perches275176b2010-03-10 15:21:06 -08001772 is_alive(__func__, "normal interrupt end");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773
1774 /* FIXME! Was it really for us? */
1775 return IRQ_HANDLED;
1776}
1777
1778static void recalibrate_floppy(void)
1779{
Joe Perchesded28632010-03-10 15:21:09 -08001780 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 do_floppy = recal_interrupt;
1782 output_byte(FD_RECALIBRATE);
Joe Perches15b26302010-03-10 15:21:01 -08001783 if (output_byte(UNIT(current_drive)) < 0)
Joe Perches2300f902010-03-10 15:20:49 -08001784 reset_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785}
1786
1787/*
1788 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1789 */
1790static void reset_interrupt(void)
1791{
Joe Perchesded28632010-03-10 15:21:09 -08001792 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 result(); /* get the status ready for set_fdc */
1794 if (FDCS->reset) {
Joe Perches1ebddd82010-03-10 15:21:07 -08001795 pr_info("reset set in interrupt, calling %pf\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 cont->error(); /* a reset just after a reset. BAD! */
1797 }
1798 cont->redo();
1799}
1800
1801/*
1802 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1803 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1804 */
1805static void reset_fdc(void)
1806{
1807 unsigned long flags;
1808
1809 do_floppy = reset_interrupt;
1810 FDCS->reset = 0;
1811 reset_fdc_info(0);
1812
1813 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1814 /* Irrelevant for systems with true DMA (i386). */
1815
1816 flags = claim_dma_lock();
1817 fd_disable_dma();
1818 release_dma_lock(flags);
1819
1820 if (FDCS->version >= FDC_82072A)
1821 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1822 else {
1823 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1824 udelay(FD_RESET_DELAY);
1825 fd_outb(FDCS->dor, FD_DOR);
1826 }
1827}
1828
1829static void show_floppy(void)
1830{
1831 int i;
1832
Joe Perchesb46df352010-03-10 15:20:46 -08001833 pr_info("\n");
1834 pr_info("floppy driver state\n");
1835 pr_info("-------------------\n");
Joe Perches1ebddd82010-03-10 15:21:07 -08001836 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%pf\n",
Joe Perchesb46df352010-03-10 15:20:46 -08001837 jiffies, interruptjiffies, jiffies - interruptjiffies,
1838 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839
Joe Perchesb46df352010-03-10 15:20:46 -08001840 pr_info("timeout_message=%s\n", timeout_message);
1841 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001843 pr_info("%2x %2x %lu\n",
1844 output_log[(i + output_log_pos) % OLOGSIZE].data,
1845 output_log[(i + output_log_pos) % OLOGSIZE].status,
1846 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1847 pr_info("last result at %lu\n", resultjiffies);
1848 pr_info("last redo_fd_request at %lu\n", lastredo);
1849 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1850 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851
Joe Perchesb46df352010-03-10 15:20:46 -08001852 pr_info("status=%x\n", fd_inb(FD_STATUS));
1853 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 if (do_floppy)
Joe Perches1ebddd82010-03-10 15:21:07 -08001855 pr_info("do_floppy=%pf\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001856 if (work_pending(&floppy_work))
Joe Perches1ebddd82010-03-10 15:21:07 -08001857 pr_info("floppy_work.func=%pf\n", floppy_work.func);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 if (timer_pending(&fd_timer))
Joe Perches1ebddd82010-03-10 15:21:07 -08001859 pr_info("fd_timer.function=%pf\n", fd_timer.function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 if (timer_pending(&fd_timeout)) {
Joe Perches1ebddd82010-03-10 15:21:07 -08001861 pr_info("timer_function=%pf\n", fd_timeout.function);
Joe Perchesb46df352010-03-10 15:20:46 -08001862 pr_info("expires=%lu\n", fd_timeout.expires - jiffies);
1863 pr_info("now=%lu\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 }
Joe Perchesb46df352010-03-10 15:20:46 -08001865 pr_info("cont=%p\n", cont);
1866 pr_info("current_req=%p\n", current_req);
1867 pr_info("command_status=%d\n", command_status);
1868 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869}
1870
1871static void floppy_shutdown(unsigned long data)
1872{
1873 unsigned long flags;
1874
Joe Perches29f1c782010-03-10 15:21:00 -08001875 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 show_floppy();
1877 cancel_activity();
1878
1879 floppy_enable_hlt();
1880
1881 flags = claim_dma_lock();
1882 fd_disable_dma();
1883 release_dma_lock(flags);
1884
1885 /* avoid dma going to a random drive after shutdown */
1886
Joe Perches29f1c782010-03-10 15:21:00 -08001887 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 DPRINT("floppy timeout called\n");
1889 FDCS->reset = 1;
1890 if (cont) {
1891 cont->done(0);
1892 cont->redo(); /* this will recall reset when needed */
1893 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001894 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 process_fd_request();
1896 }
Joe Perches275176b2010-03-10 15:21:06 -08001897 is_alive(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898}
1899
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001901static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001903 int mask;
1904 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905
1906 mask = 0xfc;
1907 data = UNIT(current_drive);
1908 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1909 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1910 set_debugt();
1911 /* no read since this drive is running */
1912 DRS->first_read_date = 0;
1913 /* note motor start time if motor is not yet running */
1914 DRS->spinup_date = jiffies;
1915 data |= (0x10 << UNIT(current_drive));
1916 }
1917 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1918 mask &= ~(0x10 << UNIT(current_drive));
1919
1920 /* starts motor and selects floppy */
1921 del_timer(motor_off_timer + current_drive);
1922 set_dor(fdc, mask, data);
1923
1924 /* wait_for_completion also schedules reset if needed. */
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001925 return fd_wait_for_completion(DRS->select_date + DP->select_delay,
1926 (timeout_fn)function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927}
1928
1929static void floppy_ready(void)
1930{
Joe Perches045f9832010-03-10 15:20:47 -08001931 if (FDCS->reset) {
1932 reset_fdc();
1933 return;
1934 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 if (start_motor(floppy_ready))
1936 return;
1937 if (fdc_dtr())
1938 return;
1939
Joe Perches87f530d2010-03-10 15:20:54 -08001940 debug_dcl(DP->flags, "calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1942 disk_change(current_drive) && !DP->select_delay)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08001943 twaddle(); /* this clears the dcl on certain
1944 * drive/controller combinations */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945
1946#ifdef fd_chose_dma_mode
1947 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1948 unsigned long flags = claim_dma_lock();
1949 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1950 release_dma_lock(flags);
1951 }
1952#endif
1953
1954 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1955 perpendicular_mode();
1956 fdc_specify(); /* must be done here because of hut, hlt ... */
1957 seek_floppy();
1958 } else {
1959 if ((raw_cmd->flags & FD_RAW_READ) ||
1960 (raw_cmd->flags & FD_RAW_WRITE))
1961 fdc_specify();
1962 setup_rw_floppy();
1963 }
1964}
1965
1966static void floppy_start(void)
1967{
Joe Perches73507e62010-03-10 15:21:03 -08001968 reschedule_timeout(current_reqD, "floppy start");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969
1970 scandrives();
Joe Perches87f530d2010-03-10 15:20:54 -08001971 debug_dcl(DP->flags, "setting NEWCHANGE in floppy_start\n");
Joe Perchese0298532010-03-10 15:20:55 -08001972 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 floppy_ready();
1974}
1975
1976/*
1977 * ========================================================================
1978 * here ends the bottom half. Exported routines are:
1979 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
1980 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
1981 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
1982 * and set_dor.
1983 * ========================================================================
1984 */
1985/*
1986 * General purpose continuations.
1987 * ==============================
1988 */
1989
1990static void do_wakeup(void)
1991{
Joe Perches73507e62010-03-10 15:21:03 -08001992 reschedule_timeout(MAXTIMEOUT, "do wakeup");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 cont = NULL;
1994 command_status += 2;
1995 wake_up(&command_done);
1996}
1997
1998static struct cont_t wakeup_cont = {
1999 .interrupt = empty,
2000 .redo = do_wakeup,
2001 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002002 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003};
2004
2005static struct cont_t intr_cont = {
2006 .interrupt = empty,
2007 .redo = process_fd_request,
2008 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07002009 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010};
2011
Joe Perches74f63f42010-03-10 15:20:58 -08002012static int wait_til_done(void (*handler)(void), bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013{
2014 int ret;
2015
2016 schedule_bh(handler);
2017
2018 if (command_status < 2 && NO_SIGNAL) {
2019 DECLARE_WAITQUEUE(wait, current);
2020
2021 add_wait_queue(&command_done, &wait);
2022 for (;;) {
2023 set_current_state(interruptible ?
2024 TASK_INTERRUPTIBLE :
2025 TASK_UNINTERRUPTIBLE);
2026
2027 if (command_status >= 2 || !NO_SIGNAL)
2028 break;
2029
Joe Perches275176b2010-03-10 15:21:06 -08002030 is_alive(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 schedule();
2032 }
2033
2034 set_current_state(TASK_RUNNING);
2035 remove_wait_queue(&command_done, &wait);
2036 }
2037
2038 if (command_status < 2) {
2039 cancel_activity();
2040 cont = &intr_cont;
2041 reset_fdc();
2042 return -EINTR;
2043 }
2044
2045 if (FDCS->reset)
2046 command_status = FD_COMMAND_ERROR;
2047 if (command_status == FD_COMMAND_OKAY)
2048 ret = 0;
2049 else
2050 ret = -EIO;
2051 command_status = FD_COMMAND_NONE;
2052 return ret;
2053}
2054
2055static void generic_done(int result)
2056{
2057 command_status = result;
2058 cont = &wakeup_cont;
2059}
2060
2061static void generic_success(void)
2062{
2063 cont->done(1);
2064}
2065
2066static void generic_failure(void)
2067{
2068 cont->done(0);
2069}
2070
2071static void success_and_wakeup(void)
2072{
2073 generic_success();
2074 cont->redo();
2075}
2076
2077/*
2078 * formatting and rw support.
2079 * ==========================
2080 */
2081
2082static int next_valid_format(void)
2083{
2084 int probed_format;
2085
2086 probed_format = DRS->probed_format;
2087 while (1) {
2088 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2089 DRS->probed_format = 0;
2090 return 1;
2091 }
2092 if (floppy_type[DP->autodetect[probed_format]].sect) {
2093 DRS->probed_format = probed_format;
2094 return 0;
2095 }
2096 probed_format++;
2097 }
2098}
2099
2100static void bad_flp_intr(void)
2101{
2102 int err_count;
2103
2104 if (probing) {
2105 DRS->probed_format++;
2106 if (!next_valid_format())
2107 return;
2108 }
2109 err_count = ++(*errors);
2110 INFBOUND(DRWE->badness, err_count);
2111 if (err_count > DP->max_errors.abort)
2112 cont->done(0);
2113 if (err_count > DP->max_errors.reset)
2114 FDCS->reset = 1;
2115 else if (err_count > DP->max_errors.recal)
2116 DRS->track = NEED_2_RECAL;
2117}
2118
2119static void set_floppy(int drive)
2120{
2121 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002122
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 if (type)
2124 _floppy = floppy_type + type;
2125 else
2126 _floppy = current_type[drive];
2127}
2128
2129/*
2130 * formatting support.
2131 * ===================
2132 */
2133static void format_interrupt(void)
2134{
2135 switch (interpret_errors()) {
2136 case 1:
2137 cont->error();
2138 case 2:
2139 break;
2140 case 0:
2141 cont->done(1);
2142 }
2143 cont->redo();
2144}
2145
2146#define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2)
Joe Perches48c8cee2010-03-10 15:20:45 -08002147#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002149
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150static void setup_format_params(int track)
2151{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002152 int n;
2153 int il;
2154 int count;
2155 int head_shift;
2156 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 struct fparm {
2158 unsigned char track, head, sect, size;
2159 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160
2161 raw_cmd = &default_raw_cmd;
2162 raw_cmd->track = track;
2163
Joe Perches48c8cee2010-03-10 15:20:45 -08002164 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2165 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 raw_cmd->rate = _floppy->rate & 0x43;
2167 raw_cmd->cmd_count = NR_F;
2168 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2169 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2170 F_SIZECODE = FD_SIZECODE(_floppy);
2171 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2172 F_GAP = _floppy->fmt_gap;
2173 F_FILL = FD_FILL_BYTE;
2174
2175 raw_cmd->kernel_data = floppy_track_buffer;
2176 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2177
2178 /* allow for about 30ms for data transport per track */
2179 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2180
2181 /* a ``cylinder'' is two tracks plus a little stepping time */
2182 track_shift = 2 * head_shift + 3;
2183
2184 /* position of logical sector 1 on this track */
2185 n = (track_shift * format_req.track + head_shift * format_req.head)
2186 % F_SECT_PER_TRACK;
2187
2188 /* determine interleave */
2189 il = 1;
2190 if (_floppy->fmt_gap < 0x22)
2191 il++;
2192
2193 /* initialize field */
2194 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2195 here[count].track = format_req.track;
2196 here[count].head = format_req.head;
2197 here[count].sect = 0;
2198 here[count].size = F_SIZECODE;
2199 }
2200 /* place logical sectors */
2201 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2202 here[n].sect = count;
2203 n = (n + il) % F_SECT_PER_TRACK;
2204 if (here[n].sect) { /* sector busy, find next free sector */
2205 ++n;
2206 if (n >= F_SECT_PER_TRACK) {
2207 n -= F_SECT_PER_TRACK;
2208 while (here[n].sect)
2209 ++n;
2210 }
2211 }
2212 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002213 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002215 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 }
2217}
2218
2219static void redo_format(void)
2220{
2221 buffer_track = -1;
2222 setup_format_params(format_req.track << STRETCH(_floppy));
2223 floppy_start();
Joe Perchesded28632010-03-10 15:21:09 -08002224 debugt(__func__, "queue format request");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225}
2226
2227static struct cont_t format_cont = {
2228 .interrupt = format_interrupt,
2229 .redo = redo_format,
2230 .error = bad_flp_intr,
2231 .done = generic_done
2232};
2233
2234static int do_format(int drive, struct format_descr *tmp_format_req)
2235{
2236 int ret;
2237
Joe Perches74f63f42010-03-10 15:20:58 -08002238 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08002239 return -EINTR;
2240
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 set_floppy(drive);
2242 if (!_floppy ||
2243 _floppy->track > DP->tracks ||
2244 tmp_format_req->track >= _floppy->track ||
2245 tmp_format_req->head >= _floppy->head ||
2246 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2247 !_floppy->fmt_gap) {
2248 process_fd_request();
2249 return -EINVAL;
2250 }
2251 format_req = *tmp_format_req;
2252 format_errors = 0;
2253 cont = &format_cont;
2254 errors = &format_errors;
Joe Perches74f63f42010-03-10 15:20:58 -08002255 ret = wait_til_done(redo_format, true);
Joe Perches55eee802010-03-10 15:20:57 -08002256 if (ret == -EINTR)
2257 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 process_fd_request();
2259 return ret;
2260}
2261
2262/*
2263 * Buffer read/write and support
2264 * =============================
2265 */
2266
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002267static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268{
2269 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002270 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271
2272 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002273 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002274 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002275 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277
2278 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002279 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 current_req = NULL;
2281}
2282
2283/* new request_done. Can handle physical sectors which are smaller than a
2284 * logical buffer */
2285static void request_done(int uptodate)
2286{
2287 struct request_queue *q = floppy_queue;
2288 struct request *req = current_req;
2289 unsigned long flags;
2290 int block;
Joe Perches73507e62010-03-10 15:21:03 -08002291 char msg[sizeof("request done ") + sizeof(int) * 3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292
2293 probing = 0;
Joe Perches73507e62010-03-10 15:21:03 -08002294 snprintf(msg, sizeof(msg), "request done %d", uptodate);
2295 reschedule_timeout(MAXTIMEOUT, msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296
2297 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002298 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299 return;
2300 }
2301
2302 if (uptodate) {
2303 /* maintain values for invalidation on geometry
2304 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002305 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 INFBOUND(DRS->maxblock, block);
2307 if (block > _floppy->sect)
2308 DRS->maxtrack = 1;
2309
2310 /* unlock chained buffers */
2311 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002312 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 spin_unlock_irqrestore(q->queue_lock, flags);
2314 } else {
2315 if (rq_data_dir(req) == WRITE) {
2316 /* record write error information */
2317 DRWE->write_errors++;
2318 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002319 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 DRWE->first_error_generation = DRS->generation;
2321 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002322 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 DRWE->last_error_generation = DRS->generation;
2324 }
2325 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002326 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 spin_unlock_irqrestore(q->queue_lock, flags);
2328 }
2329}
2330
2331/* Interrupt handler evaluating the result of the r/w operation */
2332static void rw_interrupt(void)
2333{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002334 int eoc;
2335 int ssize;
2336 int heads;
2337 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338
2339 if (R_HEAD >= 2) {
2340 /* some Toshiba floppy controllers occasionnally seem to
2341 * return bogus interrupts after read/write operations, which
2342 * can be recognized by a bad head number (>= 2) */
2343 return;
2344 }
2345
2346 if (!DRS->first_read_date)
2347 DRS->first_read_date = jiffies;
2348
2349 nr_sectors = 0;
2350 CODE2SIZE;
2351
2352 if (ST1 & ST1_EOC)
2353 eoc = 1;
2354 else
2355 eoc = 0;
2356
2357 if (COMMAND & 0x80)
2358 heads = 2;
2359 else
2360 heads = 1;
2361
2362 nr_sectors = (((R_TRACK - TRACK) * heads +
2363 R_HEAD - HEAD) * SECT_PER_TRACK +
2364 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2365
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002367 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 DPRINT("long rw: %x instead of %lx\n",
2369 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002370 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2371 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2372 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2373 pr_info("heads=%d eoc=%d\n", heads, eoc);
2374 pr_info("spt=%d st=%d ss=%d\n",
2375 SECT_PER_TRACK, fsector_t, ssize);
2376 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378
2379 nr_sectors -= in_sector_offset;
2380 INFBOUND(nr_sectors, 0);
2381 SUPBOUND(current_count_sectors, nr_sectors);
2382
2383 switch (interpret_errors()) {
2384 case 2:
2385 cont->redo();
2386 return;
2387 case 1:
2388 if (!current_count_sectors) {
2389 cont->error();
2390 cont->redo();
2391 return;
2392 }
2393 break;
2394 case 0:
2395 if (!current_count_sectors) {
2396 cont->redo();
2397 return;
2398 }
2399 current_type[current_drive] = _floppy;
2400 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2401 break;
2402 }
2403
2404 if (probing) {
2405 if (DP->flags & FTD_MSG)
2406 DPRINT("Auto-detected floppy type %s in fd%d\n",
2407 _floppy->name, current_drive);
2408 current_type[current_drive] = _floppy;
2409 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2410 probing = 0;
2411 }
2412
2413 if (CT(COMMAND) != FD_READ ||
2414 raw_cmd->kernel_data == current_req->buffer) {
2415 /* transfer directly from buffer */
2416 cont->done(1);
2417 } else if (CT(COMMAND) == FD_READ) {
2418 buffer_track = raw_cmd->track;
2419 buffer_drive = current_drive;
2420 INFBOUND(buffer_max, nr_sectors + fsector_t);
2421 }
2422 cont->redo();
2423}
2424
2425/* Compute maximal contiguous buffer size. */
2426static int buffer_chain_size(void)
2427{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 struct bio_vec *bv;
NeilBrown5705f702007-09-25 12:35:59 +02002429 int size;
2430 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 char *base;
2432
2433 base = bio_data(current_req->bio);
2434 size = 0;
2435
NeilBrown5705f702007-09-25 12:35:59 +02002436 rq_for_each_segment(bv, current_req, iter) {
2437 if (page_address(bv->bv_page) + bv->bv_offset != base + size)
2438 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439
NeilBrown5705f702007-09-25 12:35:59 +02002440 size += bv->bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 }
2442
2443 return size >> 9;
2444}
2445
2446/* Compute the maximal transfer size */
2447static int transfer_size(int ssize, int max_sector, int max_size)
2448{
2449 SUPBOUND(max_sector, fsector_t + max_size);
2450
2451 /* alignment */
2452 max_sector -= (max_sector % _floppy->sect) % ssize;
2453
2454 /* transfer size, beginning not aligned */
2455 current_count_sectors = max_sector - fsector_t;
2456
2457 return max_sector;
2458}
2459
2460/*
2461 * Move data from/to the track buffer to/from the buffer cache.
2462 */
2463static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2464{
2465 int remaining; /* number of transferred 512-byte sectors */
2466 struct bio_vec *bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002467 char *buffer;
2468 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002469 int size;
2470 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471
2472 max_sector = transfer_size(ssize,
2473 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002474 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475
2476 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002477 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002479 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480
2481 remaining = current_count_sectors << 9;
Tejun Heo1011c1b2009-05-07 22:24:45 +09002482 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002484 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2485 pr_info("remaining=%d\n", remaining >> 9);
2486 pr_info("current_req->nr_sectors=%u\n",
2487 blk_rq_sectors(current_req));
2488 pr_info("current_req->current_nr_sectors=%u\n",
2489 blk_rq_cur_sectors(current_req));
2490 pr_info("max_sector=%d\n", max_sector);
2491 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493
2494 buffer_max = max(max_sector, buffer_max);
2495
2496 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2497
Tejun Heo1011c1b2009-05-07 22:24:45 +09002498 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499
NeilBrown5705f702007-09-25 12:35:59 +02002500 rq_for_each_segment(bv, current_req, iter) {
2501 if (!remaining)
2502 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503
NeilBrown5705f702007-09-25 12:35:59 +02002504 size = bv->bv_len;
2505 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506
NeilBrown5705f702007-09-25 12:35:59 +02002507 buffer = page_address(bv->bv_page) + bv->bv_offset;
NeilBrown5705f702007-09-25 12:35:59 +02002508 if (dma_buffer + size >
2509 floppy_track_buffer + (max_buffer_sectors << 10) ||
2510 dma_buffer < floppy_track_buffer) {
2511 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002512 (int)((floppy_track_buffer - dma_buffer) >> 9));
2513 pr_info("fsector_t=%d buffer_min=%d\n",
2514 fsector_t, buffer_min);
2515 pr_info("current_count_sectors=%ld\n",
2516 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002518 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002519 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002520 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002521 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 }
NeilBrown5705f702007-09-25 12:35:59 +02002523 if (((unsigned long)buffer) % 512)
2524 DPRINT("%p buffer not aligned\n", buffer);
Joe Perches1a23d132010-03-10 15:21:04 -08002525
NeilBrown5705f702007-09-25 12:35:59 +02002526 if (CT(COMMAND) == FD_READ)
2527 memcpy(buffer, dma_buffer, size);
2528 else
2529 memcpy(dma_buffer, buffer, size);
2530
2531 remaining -= size;
2532 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 if (remaining) {
2535 if (remaining > 0)
2536 max_sector -= remaining >> 9;
2537 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2538 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539}
2540
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541/* work around a bug in pseudo DMA
2542 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2543 * sending data. Hence we need a different way to signal the
2544 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2545 * does not work with MT, hence we can only transfer one head at
2546 * a time
2547 */
2548static void virtualdmabug_workaround(void)
2549{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002550 int hard_sectors;
2551 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552
2553 if (CT(COMMAND) == FD_WRITE) {
2554 COMMAND &= ~0x80; /* switch off multiple track mode */
2555
2556 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2557 end_sector = SECTOR + hard_sectors - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002559 pr_info("too many sectors %d > %d\n",
2560 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 return;
2562 }
Joe Perches48c8cee2010-03-10 15:20:45 -08002563 SECT_PER_TRACK = end_sector;
2564 /* make sure SECT_PER_TRACK
2565 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 }
2567}
2568
2569/*
2570 * Formulate a read/write request.
2571 * this routine decides where to load the data (directly to buffer, or to
2572 * tmp floppy area), how much data to load (the size of the buffer, the whole
2573 * track, or a single sector)
2574 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2575 * allocation on the fly, it should be done here. No other part should need
2576 * modification.
2577 */
2578
2579static int make_raw_rw_request(void)
2580{
2581 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002582 int max_sector;
2583 int max_size;
2584 int tracksize;
2585 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586
2587 if (max_buffer_sectors == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002588 pr_info("VFS: Block I/O scheduled on unopened device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 return 0;
2590 }
2591
2592 set_fdc((long)current_req->rq_disk->private_data);
2593
2594 raw_cmd = &default_raw_cmd;
2595 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
2596 FD_RAW_NEED_SEEK;
2597 raw_cmd->cmd_count = NR_RW;
2598 if (rq_data_dir(current_req) == READ) {
2599 raw_cmd->flags |= FD_RAW_READ;
2600 COMMAND = FM_MODE(_floppy, FD_READ);
2601 } else if (rq_data_dir(current_req) == WRITE) {
2602 raw_cmd->flags |= FD_RAW_WRITE;
2603 COMMAND = FM_MODE(_floppy, FD_WRITE);
2604 } else {
Joe Perches275176b2010-03-10 15:21:06 -08002605 DPRINT("%s: unknown command\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 return 0;
2607 }
2608
2609 max_sector = _floppy->sect * _floppy->head;
2610
Tejun Heo83096eb2009-05-07 22:24:39 +09002611 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2612 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002614 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 current_count_sectors = 1;
2616 return 1;
2617 } else
2618 return 0;
2619 }
2620 HEAD = fsector_t / _floppy->sect;
2621
Keith Wansbrough9e491842008-09-22 14:57:17 -07002622 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Joe Perchese0298532010-03-10 15:20:55 -08002623 test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags)) &&
2624 fsector_t < _floppy->sect)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 max_sector = _floppy->sect;
2626
2627 /* 2M disks have phantom sectors on the first track */
2628 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2629 max_sector = 2 * _floppy->sect / 3;
2630 if (fsector_t >= max_sector) {
2631 current_count_sectors =
2632 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002633 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 return 1;
2635 }
2636 SIZECODE = 2;
2637 } else
2638 SIZECODE = FD_SIZECODE(_floppy);
2639 raw_cmd->rate = _floppy->rate & 0x43;
2640 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2641 raw_cmd->rate = 1;
2642
2643 if (SIZECODE)
2644 SIZECODE2 = 0xff;
2645 else
2646 SIZECODE2 = 0x80;
2647 raw_cmd->track = TRACK << STRETCH(_floppy);
2648 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2649 GAP = _floppy->gap;
2650 CODE2SIZE;
2651 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2652 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002653 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654
2655 /* tracksize describes the size which can be filled up with sectors
2656 * of size ssize.
2657 */
2658 tracksize = _floppy->sect - _floppy->sect % ssize;
2659 if (tracksize < _floppy->sect) {
2660 SECT_PER_TRACK++;
2661 if (tracksize <= fsector_t % _floppy->sect)
2662 SECTOR--;
2663
2664 /* if we are beyond tracksize, fill up using smaller sectors */
2665 while (tracksize <= fsector_t % _floppy->sect) {
2666 while (tracksize + ssize > _floppy->sect) {
2667 SIZECODE--;
2668 ssize >>= 1;
2669 }
2670 SECTOR++;
2671 SECT_PER_TRACK++;
2672 tracksize += ssize;
2673 }
2674 max_sector = HEAD * _floppy->sect + tracksize;
2675 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2676 max_sector = _floppy->sect;
2677 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2678 /* for virtual DMA bug workaround */
2679 max_sector = _floppy->sect;
2680 }
2681
2682 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2683 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002684 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 if ((raw_cmd->track == buffer_track) &&
2686 (current_drive == buffer_drive) &&
2687 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2688 /* data already in track buffer */
2689 if (CT(COMMAND) == FD_READ) {
2690 copy_buffer(1, max_sector, buffer_max);
2691 return 1;
2692 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002693 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 if (CT(COMMAND) == FD_WRITE) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002695 unsigned int sectors;
2696
2697 sectors = fsector_t + blk_rq_sectors(current_req);
2698 if (sectors > ssize && sectors < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 max_size = ssize + ssize;
2700 else
2701 max_size = ssize;
2702 }
2703 raw_cmd->flags &= ~FD_RAW_WRITE;
2704 raw_cmd->flags |= FD_RAW_READ;
2705 COMMAND = FM_MODE(_floppy, FD_READ);
2706 } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) {
2707 unsigned long dma_limit;
2708 int direct, indirect;
2709
2710 indirect =
2711 transfer_size(ssize, max_sector,
2712 max_buffer_sectors * 2) - fsector_t;
2713
2714 /*
2715 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2716 * on a 64 bit machine!
2717 */
2718 max_size = buffer_chain_size();
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002719 dma_limit = (MAX_DMA_ADDRESS -
2720 ((unsigned long)current_req->buffer)) >> 9;
Joe Perchesa81ee542010-03-10 15:20:46 -08002721 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 /* 64 kb boundaries */
2724 if (CROSS_64KB(current_req->buffer, max_size << 9))
2725 max_size = (K_64 -
2726 ((unsigned long)current_req->buffer) %
2727 K_64) >> 9;
2728 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2729 /*
2730 * We try to read tracks, but if we get too many errors, we
2731 * go back to reading just one sector at a time.
2732 *
2733 * This means we should be able to read a sector even if there
2734 * are other bad sectors on this track.
2735 */
2736 if (!direct ||
2737 (indirect * 2 > direct * 3 &&
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002738 *errors < DP->max_errors.read_track &&
2739 ((!probing ||
2740 (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002741 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 } else {
2743 raw_cmd->kernel_data = current_req->buffer;
2744 raw_cmd->length = current_count_sectors << 9;
2745 if (raw_cmd->length == 0) {
Joe Perches275176b2010-03-10 15:21:06 -08002746 DPRINT("%s: zero dma transfer attempted\n", __func__);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002747 DPRINT("indirect=%d direct=%d fsector_t=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 indirect, direct, fsector_t);
2749 return 0;
2750 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 virtualdmabug_workaround();
2752 return 2;
2753 }
2754 }
2755
2756 if (CT(COMMAND) == FD_READ)
2757 max_size = max_sector; /* unbounded */
2758
2759 /* claim buffer track if needed */
2760 if (buffer_track != raw_cmd->track || /* bad track */
2761 buffer_drive != current_drive || /* bad drive */
2762 fsector_t > buffer_max ||
2763 fsector_t < buffer_min ||
2764 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002765 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 max_sector > 2 * max_buffer_sectors + buffer_min &&
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002767 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
2768 /* not enough space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 buffer_track = -1;
2770 buffer_drive = current_drive;
2771 buffer_max = buffer_min = aligned_sector_t;
2772 }
2773 raw_cmd->kernel_data = floppy_track_buffer +
Joe Perchesbb57f0c62010-03-10 15:20:50 -08002774 ((aligned_sector_t - buffer_min) << 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775
2776 if (CT(COMMAND) == FD_WRITE) {
2777 /* copy write buffer to track buffer.
2778 * if we get here, we know that the write
2779 * is either aligned or the data already in the buffer
2780 * (buffer will be overwritten) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 if (in_sector_offset && buffer_track == -1)
2782 DPRINT("internal error offset !=0 on write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 buffer_track = raw_cmd->track;
2784 buffer_drive = current_drive;
2785 copy_buffer(ssize, max_sector,
2786 2 * max_buffer_sectors + buffer_min);
2787 } else
2788 transfer_size(ssize, max_sector,
2789 2 * max_buffer_sectors + buffer_min -
2790 aligned_sector_t);
2791
2792 /* round up current_count_sectors to get dma xfer size */
2793 raw_cmd->length = in_sector_offset + current_count_sectors;
2794 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2795 raw_cmd->length <<= 9;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 if ((raw_cmd->length < current_count_sectors << 9) ||
2797 (raw_cmd->kernel_data != current_req->buffer &&
2798 CT(COMMAND) == FD_WRITE &&
2799 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2800 aligned_sector_t < buffer_min)) ||
2801 raw_cmd->length % (128 << SIZECODE) ||
2802 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2803 DPRINT("fractionary current count b=%lx s=%lx\n",
2804 raw_cmd->length, current_count_sectors);
2805 if (raw_cmd->kernel_data != current_req->buffer)
Joe Perchesb46df352010-03-10 15:20:46 -08002806 pr_info("addr=%d, length=%ld\n",
2807 (int)((raw_cmd->kernel_data -
2808 floppy_track_buffer) >> 9),
2809 current_count_sectors);
2810 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2811 fsector_t, aligned_sector_t, max_sector, max_size);
2812 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2813 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2814 COMMAND, SECTOR, HEAD, TRACK);
2815 pr_info("buffer drive=%d\n", buffer_drive);
2816 pr_info("buffer track=%d\n", buffer_track);
2817 pr_info("buffer_min=%d\n", buffer_min);
2818 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 return 0;
2820 }
2821
2822 if (raw_cmd->kernel_data != current_req->buffer) {
2823 if (raw_cmd->kernel_data < floppy_track_buffer ||
2824 current_count_sectors < 0 ||
2825 raw_cmd->length < 0 ||
2826 raw_cmd->kernel_data + raw_cmd->length >
2827 floppy_track_buffer + (max_buffer_sectors << 10)) {
2828 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002829 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2830 fsector_t, buffer_min, raw_cmd->length >> 9);
2831 pr_info("current_count_sectors=%ld\n",
2832 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002834 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002836 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 return 0;
2838 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002839 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002840 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 DPRINT("buffer overrun in direct transfer\n");
2842 return 0;
2843 } else if (raw_cmd->length < current_count_sectors << 9) {
2844 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002845 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2846 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 }
2848 if (raw_cmd->length == 0) {
2849 DPRINT("zero dma transfer attempted from make_raw_request\n");
2850 return 0;
2851 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852
2853 virtualdmabug_workaround();
2854 return 2;
2855}
2856
2857static void redo_fd_request(void)
2858{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 int drive;
2860 int tmp;
2861
2862 lastredo = jiffies;
2863 if (current_drive < N_DRIVE)
2864 floppy_off(current_drive);
2865
Joe Perches0da31322010-03-10 15:21:03 -08002866do_request:
2867 if (!current_req) {
2868 struct request *req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869
Joe Perches0da31322010-03-10 15:21:03 -08002870 spin_lock_irq(floppy_queue->queue_lock);
2871 req = blk_fetch_request(floppy_queue);
2872 spin_unlock_irq(floppy_queue->queue_lock);
2873 if (!req) {
2874 do_floppy = NULL;
2875 unlock_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 }
Joe Perches0da31322010-03-10 15:21:03 -08002878 current_req = req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 }
Joe Perches0da31322010-03-10 15:21:03 -08002880 drive = (long)current_req->rq_disk->private_data;
2881 set_fdc(drive);
Joe Perches73507e62010-03-10 15:21:03 -08002882 reschedule_timeout(current_reqD, "redo fd request");
Joe Perches0da31322010-03-10 15:21:03 -08002883
2884 set_floppy(drive);
2885 raw_cmd = &default_raw_cmd;
2886 raw_cmd->flags = 0;
2887 if (start_motor(redo_fd_request))
2888 return;
2889
2890 disk_change(current_drive);
2891 if (test_bit(current_drive, &fake_change) ||
2892 test_bit(FD_DISK_CHANGED_BIT, &DRS->flags)) {
2893 DPRINT("disk absent or changed during operation\n");
2894 request_done(0);
2895 goto do_request;
2896 }
2897 if (!_floppy) { /* Autodetection */
2898 if (!probing) {
2899 DRS->probed_format = 0;
2900 if (next_valid_format()) {
2901 DPRINT("no autodetectable formats\n");
2902 _floppy = NULL;
2903 request_done(0);
2904 goto do_request;
2905 }
2906 }
2907 probing = 1;
2908 _floppy = floppy_type + DP->autodetect[DRS->probed_format];
2909 } else
2910 probing = 0;
2911 errors = &(current_req->errors);
2912 tmp = make_raw_rw_request();
2913 if (tmp < 2) {
2914 request_done(tmp);
2915 goto do_request;
2916 }
2917
2918 if (test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags))
2919 twaddle();
2920 schedule_bh(floppy_start);
Joe Perchesded28632010-03-10 15:21:09 -08002921 debugt(__func__, "queue fd request");
Joe Perches0da31322010-03-10 15:21:03 -08002922 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923}
2924
2925static struct cont_t rw_cont = {
2926 .interrupt = rw_interrupt,
2927 .redo = redo_fd_request,
2928 .error = bad_flp_intr,
2929 .done = request_done
2930};
2931
2932static void process_fd_request(void)
2933{
2934 cont = &rw_cont;
2935 schedule_bh(redo_fd_request);
2936}
2937
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002938static void do_fd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939{
2940 if (max_buffer_sectors == 0) {
Joe Perches275176b2010-03-10 15:21:06 -08002941 pr_info("VFS: %s called on non-open device\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 return;
2943 }
2944
2945 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08002946 pr_info("warning: usage count=0, current_req=%p exiting\n",
2947 current_req);
2948 pr_info("sect=%ld type=%x flags=%x\n",
2949 (long)blk_rq_pos(current_req), current_req->cmd_type,
2950 current_req->cmd_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 return;
2952 }
2953 if (test_bit(0, &fdc_busy)) {
2954 /* fdc busy, this new request will be treated when the
2955 current one is done */
Joe Perches275176b2010-03-10 15:21:06 -08002956 is_alive(__func__, "old request running");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 return;
2958 }
Joe Perches74f63f42010-03-10 15:20:58 -08002959 lock_fdc(MAXTIMEOUT, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 process_fd_request();
Joe Perches275176b2010-03-10 15:21:06 -08002961 is_alive(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962}
2963
2964static struct cont_t poll_cont = {
2965 .interrupt = success_and_wakeup,
2966 .redo = floppy_ready,
2967 .error = generic_failure,
2968 .done = generic_done
2969};
2970
Joe Perches74f63f42010-03-10 15:20:58 -08002971static int poll_drive(bool interruptible, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 /* no auto-sense, just clear dcl */
2974 raw_cmd = &default_raw_cmd;
2975 raw_cmd->flags = flag;
2976 raw_cmd->track = 0;
2977 raw_cmd->cmd_count = 0;
2978 cont = &poll_cont;
Joe Perches87f530d2010-03-10 15:20:54 -08002979 debug_dcl(DP->flags, "setting NEWCHANGE in poll_drive\n");
Joe Perchese0298532010-03-10 15:20:55 -08002980 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Joe Perches55eee802010-03-10 15:20:57 -08002981
2982 return wait_til_done(floppy_ready, interruptible);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983}
2984
2985/*
2986 * User triggered reset
2987 * ====================
2988 */
2989
2990static void reset_intr(void)
2991{
Joe Perchesb46df352010-03-10 15:20:46 -08002992 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993}
2994
2995static struct cont_t reset_cont = {
2996 .interrupt = reset_intr,
2997 .redo = success_and_wakeup,
2998 .error = generic_failure,
2999 .done = generic_done
3000};
3001
Joe Perches74f63f42010-03-10 15:20:58 -08003002static int user_reset_fdc(int drive, int arg, bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003{
3004 int ret;
3005
Joe Perches52a0d612010-03-10 15:20:53 -08003006 if (lock_fdc(drive, interruptible))
3007 return -EINTR;
3008
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 if (arg == FD_RESET_ALWAYS)
3010 FDCS->reset = 1;
3011 if (FDCS->reset) {
3012 cont = &reset_cont;
Joe Perches55eee802010-03-10 15:20:57 -08003013 ret = wait_til_done(reset_fdc, interruptible);
3014 if (ret == -EINTR)
3015 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 }
3017 process_fd_request();
Joe Perches52a0d612010-03-10 15:20:53 -08003018 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019}
3020
3021/*
3022 * Misc Ioctl's and support
3023 * ========================
3024 */
3025static inline int fd_copyout(void __user *param, const void *address,
3026 unsigned long size)
3027{
3028 return copy_to_user(param, address, size) ? -EFAULT : 0;
3029}
3030
Joe Perches48c8cee2010-03-10 15:20:45 -08003031static inline int fd_copyin(void __user *param, void *address,
3032 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033{
3034 return copy_from_user(address, param, size) ? -EFAULT : 0;
3035}
3036
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037static inline const char *drive_name(int type, int drive)
3038{
3039 struct floppy_struct *floppy;
3040
3041 if (type)
3042 floppy = floppy_type + type;
3043 else {
3044 if (UDP->native_format)
3045 floppy = floppy_type + UDP->native_format;
3046 else
3047 return "(null)";
3048 }
3049 if (floppy->name)
3050 return floppy->name;
3051 else
3052 return "(null)";
3053}
3054
3055/* raw commands */
3056static void raw_cmd_done(int flag)
3057{
3058 int i;
3059
3060 if (!flag) {
3061 raw_cmd->flags |= FD_RAW_FAILURE;
3062 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3063 } else {
3064 raw_cmd->reply_count = inr;
3065 if (raw_cmd->reply_count > MAX_REPLIES)
3066 raw_cmd->reply_count = 0;
3067 for (i = 0; i < raw_cmd->reply_count; i++)
3068 raw_cmd->reply[i] = reply_buffer[i];
3069
3070 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3071 unsigned long flags;
3072 flags = claim_dma_lock();
3073 raw_cmd->length = fd_get_dma_residue();
3074 release_dma_lock(flags);
3075 }
3076
3077 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3078 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3079 raw_cmd->flags |= FD_RAW_FAILURE;
3080
3081 if (disk_change(current_drive))
3082 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3083 else
3084 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3085 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3086 motor_off_callback(current_drive);
3087
3088 if (raw_cmd->next &&
3089 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3090 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3091 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3092 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3093 raw_cmd = raw_cmd->next;
3094 return;
3095 }
3096 }
3097 generic_done(flag);
3098}
3099
3100static struct cont_t raw_cmd_cont = {
3101 .interrupt = success_and_wakeup,
3102 .redo = floppy_start,
3103 .error = generic_failure,
3104 .done = raw_cmd_done
3105};
3106
Joe Perchesce2f11f2010-03-10 15:21:08 -08003107static inline int raw_cmd_copyout(int cmd, void __user *param,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 struct floppy_raw_cmd *ptr)
3109{
3110 int ret;
3111
3112 while (ptr) {
Joe Perchesce2f11f2010-03-10 15:21:08 -08003113 ret = copy_to_user(param, ptr, sizeof(*ptr));
Joe Perches86b12b42010-03-10 15:20:56 -08003114 if (ret)
3115 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 param += sizeof(struct floppy_raw_cmd);
3117 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003118 if (ptr->length >= 0 &&
3119 ptr->length <= ptr->buffer_length) {
3120 long length = ptr->buffer_length - ptr->length;
Joe Perches4575b552010-03-10 15:20:55 -08003121 ret = fd_copyout(ptr->data, ptr->kernel_data,
3122 length);
3123 if (ret)
3124 return ret;
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003125 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 }
3127 ptr = ptr->next;
3128 }
Joe Perches7f252712010-03-10 15:21:08 -08003129
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 return 0;
3131}
3132
3133static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3134{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003135 struct floppy_raw_cmd *next;
3136 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137
3138 this = *ptr;
3139 *ptr = NULL;
3140 while (this) {
3141 if (this->buffer_length) {
3142 fd_dma_mem_free((unsigned long)this->kernel_data,
3143 this->buffer_length);
3144 this->buffer_length = 0;
3145 }
3146 next = this->next;
3147 kfree(this);
3148 this = next;
3149 }
3150}
3151
Joe Perchesce2f11f2010-03-10 15:21:08 -08003152static inline int raw_cmd_copyin(int cmd, void __user *param,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 struct floppy_raw_cmd **rcmd)
3154{
3155 struct floppy_raw_cmd *ptr;
3156 int ret;
3157 int i;
3158
3159 *rcmd = NULL;
Joe Perches7f252712010-03-10 15:21:08 -08003160
3161loop:
3162 ptr = kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3163 if (!ptr)
3164 return -ENOMEM;
3165 *rcmd = ptr;
3166 ret = copy_from_user(ptr, param, sizeof(*ptr));
3167 if (ret)
3168 return -EFAULT;
3169 ptr->next = NULL;
3170 ptr->buffer_length = 0;
3171 param += sizeof(struct floppy_raw_cmd);
3172 if (ptr->cmd_count > 33)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 /* the command may now also take up the space
3174 * initially intended for the reply & the
3175 * reply count. Needed for long 82078 commands
3176 * such as RESTORE, which takes ... 17 command
3177 * bytes. Murphy's law #137: When you reserve
3178 * 16 bytes for a structure, you'll one day
3179 * discover that you really need 17...
3180 */
Joe Perches7f252712010-03-10 15:21:08 -08003181 return -EINVAL;
3182
3183 for (i = 0; i < 16; i++)
3184 ptr->reply[i] = 0;
3185 ptr->resultcode = 0;
3186 ptr->kernel_data = NULL;
3187
3188 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3189 if (ptr->length <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 return -EINVAL;
Joe Perches7f252712010-03-10 15:21:08 -08003191 ptr->kernel_data = (char *)fd_dma_mem_alloc(ptr->length);
3192 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3193 if (!ptr->kernel_data)
3194 return -ENOMEM;
3195 ptr->buffer_length = ptr->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 }
Joe Perches7f252712010-03-10 15:21:08 -08003197 if (ptr->flags & FD_RAW_WRITE) {
3198 ret = fd_copyin(ptr->data, ptr->kernel_data, ptr->length);
3199 if (ret)
3200 return ret;
3201 }
3202
3203 if (ptr->flags & FD_RAW_MORE) {
3204 rcmd = &(ptr->next);
3205 ptr->rate &= 0x43;
3206 goto loop;
3207 }
3208
3209 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210}
3211
3212static int raw_cmd_ioctl(int cmd, void __user *param)
3213{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003215 int drive;
3216 int ret2;
3217 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218
3219 if (FDCS->rawcmd <= 1)
3220 FDCS->rawcmd = 1;
3221 for (drive = 0; drive < N_DRIVE; drive++) {
3222 if (FDC(drive) != fdc)
3223 continue;
3224 if (drive == current_drive) {
3225 if (UDRS->fd_ref > 1) {
3226 FDCS->rawcmd = 2;
3227 break;
3228 }
3229 } else if (UDRS->fd_ref) {
3230 FDCS->rawcmd = 2;
3231 break;
3232 }
3233 }
3234
3235 if (FDCS->reset)
3236 return -EIO;
3237
3238 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3239 if (ret) {
3240 raw_cmd_free(&my_raw_cmd);
3241 return ret;
3242 }
3243
3244 raw_cmd = my_raw_cmd;
3245 cont = &raw_cmd_cont;
Joe Perches74f63f42010-03-10 15:20:58 -08003246 ret = wait_til_done(floppy_start, true);
Joe Perches87f530d2010-03-10 15:20:54 -08003247 debug_dcl(DP->flags, "calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248
3249 if (ret != -EINTR && FDCS->reset)
3250 ret = -EIO;
3251
3252 DRS->track = NO_TRACK;
3253
3254 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3255 if (!ret)
3256 ret = ret2;
3257 raw_cmd_free(&my_raw_cmd);
3258 return ret;
3259}
3260
3261static int invalidate_drive(struct block_device *bdev)
3262{
3263 /* invalidate the buffer track to force a reread */
3264 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3265 process_fd_request();
3266 check_disk_change(bdev);
3267 return 0;
3268}
3269
3270static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
3271 int drive, int type, struct block_device *bdev)
3272{
3273 int cnt;
3274
3275 /* sanity checking for parameters. */
3276 if (g->sect <= 0 ||
3277 g->head <= 0 ||
3278 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3279 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003280 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281 return -EINVAL;
3282 if (type) {
3283 if (!capable(CAP_SYS_ADMIN))
3284 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003285 mutex_lock(&open_lock);
Joe Perches74f63f42010-03-10 15:20:58 -08003286 if (lock_fdc(drive, true)) {
Jiri Slaby8516a502009-06-30 11:41:44 -07003287 mutex_unlock(&open_lock);
3288 return -EINTR;
3289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 floppy_type[type] = *g;
3291 floppy_type[type].name = "user format";
3292 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3293 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3294 floppy_type[type].size + 1;
3295 process_fd_request();
3296 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3297 struct block_device *bdev = opened_bdev[cnt];
3298 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3299 continue;
Christoph Hellwig2ef41632005-05-05 16:15:59 -07003300 __invalidate_device(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003302 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303 } else {
3304 int oldStretch;
Joe Perches52a0d612010-03-10 15:20:53 -08003305
Joe Perches74f63f42010-03-10 15:20:58 -08003306 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003307 return -EINTR;
Joe Perches4575b552010-03-10 15:20:55 -08003308 if (cmd != FDDEFPRM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 /* notice a disk change immediately, else
3310 * we lose our settings immediately*/
Joe Perches74f63f42010-03-10 15:20:58 -08003311 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003312 return -EINTR;
3313 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 oldStretch = g->stretch;
3315 user_params[drive] = *g;
3316 if (buffer_drive == drive)
3317 SUPBOUND(buffer_max, user_params[drive].sect);
3318 current_type[drive] = &user_params[drive];
3319 floppy_sizes[drive] = user_params[drive].size;
3320 if (cmd == FDDEFPRM)
3321 DRS->keep_data = -1;
3322 else
3323 DRS->keep_data = 1;
3324 /* invalidation. Invalidate only when needed, i.e.
3325 * when there are already sectors in the buffer cache
3326 * whose number will change. This is useful, because
3327 * mtools often changes the geometry of the disk after
3328 * looking at the boot block */
3329 if (DRS->maxblock > user_params[drive].sect ||
3330 DRS->maxtrack ||
3331 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003332 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333 invalidate_drive(bdev);
3334 else
3335 process_fd_request();
3336 }
3337 return 0;
3338}
3339
3340/* handle obsolete ioctl's */
3341static int ioctl_table[] = {
3342 FDCLRPRM,
3343 FDSETPRM,
3344 FDDEFPRM,
3345 FDGETPRM,
3346 FDMSGON,
3347 FDMSGOFF,
3348 FDFMTBEG,
3349 FDFMTTRK,
3350 FDFMTEND,
3351 FDSETEMSGTRESH,
3352 FDFLUSH,
3353 FDSETMAXERRS,
3354 FDGETMAXERRS,
3355 FDGETDRVTYP,
3356 FDSETDRVPRM,
3357 FDGETDRVPRM,
3358 FDGETDRVSTAT,
3359 FDPOLLDRVSTAT,
3360 FDRESET,
3361 FDGETFDCSTAT,
3362 FDWERRORCLR,
3363 FDWERRORGET,
3364 FDRAWCMD,
3365 FDEJECT,
3366 FDTWADDLE
3367};
3368
3369static inline int normalize_ioctl(int *cmd, int *size)
3370{
3371 int i;
3372
3373 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3374 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3375 *size = _IOC_SIZE(*cmd);
3376 *cmd = ioctl_table[i];
3377 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003378 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 return -EFAULT;
3380 }
3381 return 0;
3382 }
3383 }
3384 return -EINVAL;
3385}
3386
3387static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3388{
3389 if (type)
3390 *g = &floppy_type[type];
3391 else {
Joe Perches74f63f42010-03-10 15:20:58 -08003392 if (lock_fdc(drive, false))
Joe Perches52a0d612010-03-10 15:20:53 -08003393 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003394 if (poll_drive(false, 0) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003395 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 process_fd_request();
3397 *g = current_type[drive];
3398 }
3399 if (!*g)
3400 return -ENODEV;
3401 return 0;
3402}
3403
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003404static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3405{
3406 int drive = (long)bdev->bd_disk->private_data;
3407 int type = ITYPE(drive_state[drive].fd_device);
3408 struct floppy_struct *g;
3409 int ret;
3410
3411 ret = get_floppy_geometry(drive, type, &g);
3412 if (ret)
3413 return ret;
3414
3415 geo->heads = g->head;
3416 geo->sectors = g->sect;
3417 geo->cylinders = g->track;
3418 return 0;
3419}
3420
Al Viroa4af9b42008-03-02 09:27:55 -05003421static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 unsigned long param)
3423{
Al Viroa4af9b42008-03-02 09:27:55 -05003424#define FD_IOCTL_ALLOWED (mode & (FMODE_WRITE|FMODE_WRITE_IOCTL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425
Al Viroa4af9b42008-03-02 09:27:55 -05003426 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003427 int type = ITYPE(UDRS->fd_device);
3428 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 int ret;
3430 int size;
3431 union inparam {
3432 struct floppy_struct g; /* geometry */
3433 struct format_descr f;
3434 struct floppy_max_errors max_errors;
3435 struct floppy_drive_params dp;
3436 } inparam; /* parameters coming from user space */
3437 const char *outparam; /* parameters passed back to user space */
3438
3439 /* convert compatibility eject ioctls into floppy eject ioctl.
3440 * We do this in order to provide a means to eject floppy disks before
3441 * installing the new fdutils package */
3442 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003443 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 DPRINT("obsolete eject ioctl\n");
3445 DPRINT("please use floppycontrol --eject\n");
3446 cmd = FDEJECT;
3447 }
3448
Joe Perchesa81ee542010-03-10 15:20:46 -08003449 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 return -EINVAL;
3451
Joe Perchesa81ee542010-03-10 15:20:46 -08003452 /* convert the old style command into a new style command */
Joe Perches4575b552010-03-10 15:20:55 -08003453 ret = normalize_ioctl(&cmd, &size);
3454 if (ret)
3455 return ret;
Joe Perchesa81ee542010-03-10 15:20:46 -08003456
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457 /* permission checks */
3458 if (((cmd & 0x40) && !FD_IOCTL_ALLOWED) ||
3459 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3460 return -EPERM;
3461
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003462 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3463 return -EINVAL;
3464
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465 /* copyin */
Joe Perchesb87c9e02010-03-10 15:20:50 -08003466 memset(&inparam, 0, sizeof(inparam));
Joe Perches4575b552010-03-10 15:20:55 -08003467 if (_IOC_DIR(cmd) & _IOC_WRITE) {
3468 ret = fd_copyin((void __user *)param, &inparam, size);
3469 if (ret)
3470 return ret;
3471 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472
Joe Perchesda273652010-03-10 15:20:52 -08003473 switch (cmd) {
3474 case FDEJECT:
3475 if (UDRS->fd_ref != 1)
3476 /* somebody else has this drive open */
3477 return -EBUSY;
Joe Perches74f63f42010-03-10 15:20:58 -08003478 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003479 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480
Joe Perchesda273652010-03-10 15:20:52 -08003481 /* do the actual eject. Fails on
3482 * non-Sparc architectures */
3483 ret = fd_eject(UNIT(drive));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484
Joe Perchese0298532010-03-10 15:20:55 -08003485 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3486 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Joe Perchesda273652010-03-10 15:20:52 -08003487 process_fd_request();
3488 return ret;
3489 case FDCLRPRM:
Joe Perches74f63f42010-03-10 15:20:58 -08003490 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003491 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003492 current_type[drive] = NULL;
3493 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3494 UDRS->keep_data = 0;
3495 return invalidate_drive(bdev);
3496 case FDSETPRM:
3497 case FDDEFPRM:
3498 return set_geometry(cmd, &inparam.g, drive, type, bdev);
3499 case FDGETPRM:
Joe Perches4575b552010-03-10 15:20:55 -08003500 ret = get_floppy_geometry(drive, type,
Joe Perchesda273652010-03-10 15:20:52 -08003501 (struct floppy_struct **)
Joe Perches4575b552010-03-10 15:20:55 -08003502 &outparam);
3503 if (ret)
3504 return ret;
Joe Perchesda273652010-03-10 15:20:52 -08003505 break;
3506 case FDMSGON:
3507 UDP->flags |= FTD_MSG;
3508 return 0;
3509 case FDMSGOFF:
3510 UDP->flags &= ~FTD_MSG;
3511 return 0;
3512 case FDFMTBEG:
Joe Perches74f63f42010-03-10 15:20:58 -08003513 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003514 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003515 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003516 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003517 ret = UDRS->flags;
3518 process_fd_request();
3519 if (ret & FD_VERIFY)
3520 return -ENODEV;
3521 if (!(ret & FD_DISK_WRITABLE))
3522 return -EROFS;
3523 return 0;
3524 case FDFMTTRK:
3525 if (UDRS->fd_ref != 1)
3526 return -EBUSY;
3527 return do_format(drive, &inparam.f);
3528 case FDFMTEND:
3529 case FDFLUSH:
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 return invalidate_drive(bdev);
3533 case FDSETEMSGTRESH:
3534 UDP->max_errors.reporting = (unsigned short)(param & 0x0f);
3535 return 0;
3536 case FDGETMAXERRS:
3537 outparam = (const char *)&UDP->max_errors;
3538 break;
3539 case FDSETMAXERRS:
3540 UDP->max_errors = inparam.max_errors;
3541 break;
3542 case FDGETDRVTYP:
3543 outparam = drive_name(type, drive);
3544 SUPBOUND(size, strlen(outparam) + 1);
3545 break;
3546 case FDSETDRVPRM:
3547 *UDP = inparam.dp;
3548 break;
3549 case FDGETDRVPRM:
3550 outparam = (const char *)UDP;
3551 break;
3552 case FDPOLLDRVSTAT:
Joe Perches74f63f42010-03-10 15:20:58 -08003553 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003554 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003555 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003556 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003557 process_fd_request();
3558 /* fall through */
3559 case FDGETDRVSTAT:
3560 outparam = (const char *)UDRS;
3561 break;
3562 case FDRESET:
Joe Perches74f63f42010-03-10 15:20:58 -08003563 return user_reset_fdc(drive, (int)param, true);
Joe Perchesda273652010-03-10 15:20:52 -08003564 case FDGETFDCSTAT:
3565 outparam = (const char *)UFDCS;
3566 break;
3567 case FDWERRORCLR:
3568 memset(UDRWE, 0, sizeof(*UDRWE));
3569 return 0;
3570 case FDWERRORGET:
3571 outparam = (const char *)UDRWE;
3572 break;
3573 case FDRAWCMD:
3574 if (type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575 return -EINVAL;
Joe Perches74f63f42010-03-10 15:20:58 -08003576 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003577 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003578 set_floppy(drive);
Joe Perches4575b552010-03-10 15:20:55 -08003579 i = raw_cmd_ioctl(cmd, (void __user *)param);
3580 if (i == -EINTR)
3581 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003582 process_fd_request();
3583 return i;
3584 case FDTWADDLE:
Joe Perches74f63f42010-03-10 15:20:58 -08003585 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003586 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003587 twaddle();
3588 process_fd_request();
3589 return 0;
3590 default:
3591 return -EINVAL;
3592 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593
3594 if (_IOC_DIR(cmd) & _IOC_READ)
3595 return fd_copyout((void __user *)param, outparam, size);
Joe Perchesda273652010-03-10 15:20:52 -08003596
3597 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598}
3599
3600static void __init config_types(void)
3601{
Joe Perchesb46df352010-03-10 15:20:46 -08003602 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 int drive;
3604
3605 /* read drive info out of physical CMOS */
3606 drive = 0;
3607 if (!UDP->cmos)
3608 UDP->cmos = FLOPPY0_TYPE;
3609 drive = 1;
3610 if (!UDP->cmos && FLOPPY1_TYPE)
3611 UDP->cmos = FLOPPY1_TYPE;
3612
Jesper Juhl06f748c2007-10-16 23:30:57 -07003613 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614
3615 for (drive = 0; drive < N_DRIVE; drive++) {
3616 unsigned int type = UDP->cmos;
3617 struct floppy_drive_params *params;
3618 const char *name = NULL;
3619 static char temparea[32];
3620
Tobias Klauser945f3902006-01-08 01:05:11 -08003621 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622 params = &default_drive_params[type].params;
3623 if (type) {
3624 name = default_drive_params[type].name;
3625 allowed_drive_mask |= 1 << drive;
3626 } else
3627 allowed_drive_mask &= ~(1 << drive);
3628 } else {
3629 params = &default_drive_params[0].params;
3630 sprintf(temparea, "unknown type %d (usb?)", type);
3631 name = temparea;
3632 }
3633 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003634 const char *prepend;
3635 if (!has_drive) {
3636 prepend = "";
3637 has_drive = true;
3638 pr_info("Floppy drive(s):");
3639 } else {
3640 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 }
Joe Perchesb46df352010-03-10 15:20:46 -08003642
3643 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644 }
3645 *UDP = *params;
3646 }
Joe Perchesb46df352010-03-10 15:20:46 -08003647
3648 if (has_drive)
3649 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650}
3651
Al Viroa4af9b42008-03-02 09:27:55 -05003652static int floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653{
Al Viroa4af9b42008-03-02 09:27:55 -05003654 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003656 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 if (UDRS->fd_ref < 0)
3658 UDRS->fd_ref = 0;
3659 else if (!UDRS->fd_ref--) {
3660 DPRINT("floppy_release with fd_ref == 0");
3661 UDRS->fd_ref = 0;
3662 }
3663 if (!UDRS->fd_ref)
3664 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003665 mutex_unlock(&open_lock);
Ingo Molnar3e541a42006-07-03 00:24:23 -07003666
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667 return 0;
3668}
3669
3670/*
3671 * floppy_open check for aliasing (/dev/fd0 can be the same as
3672 * /dev/PS0 etc), and disallows simultaneous access to the same
3673 * drive with different device numbers.
3674 */
Al Viroa4af9b42008-03-02 09:27:55 -05003675static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676{
Al Viroa4af9b42008-03-02 09:27:55 -05003677 int drive = (long)bdev->bd_disk->private_data;
3678 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679 int try;
3680 int res = -EBUSY;
3681 char *tmp;
3682
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003683 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003685 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686 goto out2;
3687
3688 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
Joe Perchese0298532010-03-10 15:20:55 -08003689 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3690 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691 }
3692
Al Viroa4af9b42008-03-02 09:27:55 -05003693 if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 goto out2;
3695
Al Viroa4af9b42008-03-02 09:27:55 -05003696 if (mode & FMODE_EXCL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697 UDRS->fd_ref = -1;
3698 else
3699 UDRS->fd_ref++;
3700
Al Viroa4af9b42008-03-02 09:27:55 -05003701 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702
3703 res = -ENXIO;
3704
3705 if (!floppy_track_buffer) {
3706 /* if opening an ED drive, reserve a big buffer,
3707 * else reserve a small one */
3708 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3709 try = 64; /* Only 48 actually useful */
3710 else
3711 try = 32; /* Only 24 actually useful */
3712
3713 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3714 if (!tmp && !floppy_track_buffer) {
3715 try >>= 1; /* buffer only one side */
3716 INFBOUND(try, 16);
3717 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3718 }
Joe Perchesa81ee542010-03-10 15:20:46 -08003719 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721 if (!tmp && !floppy_track_buffer) {
3722 DPRINT("Unable to allocate DMA memory\n");
3723 goto out;
3724 }
3725 if (floppy_track_buffer) {
3726 if (tmp)
3727 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3728 } else {
3729 buffer_min = buffer_max = -1;
3730 floppy_track_buffer = tmp;
3731 max_buffer_sectors = try;
3732 }
3733 }
3734
Al Viroa4af9b42008-03-02 09:27:55 -05003735 new_dev = MINOR(bdev->bd_dev);
3736 UDRS->fd_device = new_dev;
3737 set_capacity(disks[drive], floppy_sizes[new_dev]);
3738 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739 if (buffer_drive == drive)
3740 buffer_track = -1;
3741 }
3742
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743 if (UFDCS->rawcmd == 1)
3744 UFDCS->rawcmd = 2;
3745
Al Viroa4af9b42008-03-02 09:27:55 -05003746 if (!(mode & FMODE_NDELAY)) {
3747 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748 UDRS->last_checked = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003749 check_disk_change(bdev);
Joe Perchese0298532010-03-10 15:20:55 -08003750 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751 goto out;
3752 }
3753 res = -EROFS;
Joe Perchese0298532010-03-10 15:20:55 -08003754 if ((mode & FMODE_WRITE) &&
3755 !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756 goto out;
3757 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003758 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759 return 0;
3760out:
3761 if (UDRS->fd_ref < 0)
3762 UDRS->fd_ref = 0;
3763 else
3764 UDRS->fd_ref--;
3765 if (!UDRS->fd_ref)
3766 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003768 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769 return res;
3770}
3771
3772/*
3773 * Check if the disk has been changed or if a change has been faked.
3774 */
3775static int check_floppy_change(struct gendisk *disk)
3776{
3777 int drive = (long)disk->private_data;
3778
Joe Perchese0298532010-03-10 15:20:55 -08003779 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3780 test_bit(FD_VERIFY_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781 return 1;
3782
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003783 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Joe Perches74f63f42010-03-10 15:20:58 -08003784 lock_fdc(drive, false);
3785 poll_drive(false, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 }
3788
Joe Perchese0298532010-03-10 15:20:55 -08003789 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3790 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 test_bit(drive, &fake_change) ||
3792 (!ITYPE(UDRS->fd_device) && !current_type[drive]))
3793 return 1;
3794 return 0;
3795}
3796
3797/*
3798 * This implements "read block 0" for floppy_revalidate().
3799 * Needed for format autodetection, checking whether there is
3800 * a disk in the drive, and whether that disk is writable.
3801 */
3802
Joe Perchesbb57f0c62010-03-10 15:20:50 -08003803static void floppy_rb0_complete(struct bio *bio, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805 complete((struct completion *)bio->bi_private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806}
3807
3808static int __floppy_read_block_0(struct block_device *bdev)
3809{
3810 struct bio bio;
3811 struct bio_vec bio_vec;
3812 struct completion complete;
3813 struct page *page;
3814 size_t size;
3815
3816 page = alloc_page(GFP_NOIO);
3817 if (!page) {
3818 process_fd_request();
3819 return -ENOMEM;
3820 }
3821
3822 size = bdev->bd_block_size;
3823 if (!size)
3824 size = 1024;
3825
3826 bio_init(&bio);
3827 bio.bi_io_vec = &bio_vec;
3828 bio_vec.bv_page = page;
3829 bio_vec.bv_len = size;
3830 bio_vec.bv_offset = 0;
3831 bio.bi_vcnt = 1;
3832 bio.bi_idx = 0;
3833 bio.bi_size = size;
3834 bio.bi_bdev = bdev;
3835 bio.bi_sector = 0;
3836 init_completion(&complete);
3837 bio.bi_private = &complete;
3838 bio.bi_end_io = floppy_rb0_complete;
3839
3840 submit_bio(READ, &bio);
3841 generic_unplug_device(bdev_get_queue(bdev));
3842 process_fd_request();
3843 wait_for_completion(&complete);
3844
3845 __free_page(page);
3846
3847 return 0;
3848}
3849
3850/* revalidate the floppy disk, i.e. trigger format autodetection by reading
3851 * the bootblock (block 0). "Autodetection" is also needed to check whether
3852 * there is a disk in the drive at all... Thus we also do it for fixed
3853 * geometry formats */
3854static int floppy_revalidate(struct gendisk *disk)
3855{
3856 int drive = (long)disk->private_data;
3857#define NO_GEOM (!current_type[drive] && !ITYPE(UDRS->fd_device))
3858 int cf;
3859 int res = 0;
3860
Joe Perchese0298532010-03-10 15:20:55 -08003861 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3862 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
3863 test_bit(drive, &fake_change) || NO_GEOM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 if (usage_count == 0) {
Joe Perchesb46df352010-03-10 15:20:46 -08003865 pr_info("VFS: revalidate called on non-open device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866 return -EFAULT;
3867 }
Joe Perches74f63f42010-03-10 15:20:58 -08003868 lock_fdc(drive, false);
Joe Perchese0298532010-03-10 15:20:55 -08003869 cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3870 test_bit(FD_VERIFY_BIT, &UDRS->flags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871 if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)) {
3872 process_fd_request(); /*already done by another thread */
3873 return 0;
3874 }
3875 UDRS->maxblock = 0;
3876 UDRS->maxtrack = 0;
3877 if (buffer_drive == drive)
3878 buffer_track = -1;
3879 clear_bit(drive, &fake_change);
Joe Perchese0298532010-03-10 15:20:55 -08003880 clear_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 if (cf)
3882 UDRS->generation++;
3883 if (NO_GEOM) {
3884 /* auto-sensing */
3885 res = __floppy_read_block_0(opened_bdev[drive]);
3886 } else {
3887 if (cf)
Joe Perches74f63f42010-03-10 15:20:58 -08003888 poll_drive(false, FD_RAW_NEED_DISK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889 process_fd_request();
3890 }
3891 }
3892 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
3893 return res;
3894}
3895
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07003896static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07003897 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05003898 .open = floppy_open,
3899 .release = floppy_release,
3900 .locked_ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003901 .getgeo = fd_getgeo,
3902 .media_changed = check_floppy_change,
3903 .revalidate_disk = floppy_revalidate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906/*
3907 * Floppy Driver initialization
3908 * =============================
3909 */
3910
3911/* Determine the floppy disk controller type */
3912/* This routine was written by David C. Niemi */
3913static char __init get_fdc_version(void)
3914{
3915 int r;
3916
3917 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
3918 if (FDCS->reset)
3919 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003920 r = result();
3921 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922 return FDC_NONE; /* No FDC present ??? */
3923 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003924 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3926 }
3927 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003928 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3929 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930 return FDC_UNKNOWN;
3931 }
3932
3933 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003934 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3936 }
3937
3938 output_byte(FD_PERPENDICULAR);
3939 if (need_more_output() == MORE_OUTPUT) {
3940 output_byte(0);
3941 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003942 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003943 return FDC_82072A; /* 82072A as found on Sparcs. */
3944 }
3945
3946 output_byte(FD_UNLOCK);
3947 r = result();
3948 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003949 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003950 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07003951 * LOCK/UNLOCK */
3952 }
3953 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003954 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3955 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 return FDC_UNKNOWN;
3957 }
3958 output_byte(FD_PARTID);
3959 r = result();
3960 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003961 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3962 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963 return FDC_UNKNOWN;
3964 }
3965 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003966 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 return FDC_82077; /* Revised 82077AA passes all the tests */
3968 }
3969 switch (reply_buffer[0] >> 5) {
3970 case 0x0:
3971 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08003972 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973 return FDC_82078;
3974 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08003975 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976 return FDC_82078;
3977 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08003978 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 return FDC_S82078B;
3980 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08003981 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982 return FDC_87306;
3983 default:
Joe Perchesb46df352010-03-10 15:20:46 -08003984 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
3985 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986 return FDC_82078_UNKN;
3987 }
3988} /* get_fdc_version */
3989
3990/* lilo configuration */
3991
3992static void __init floppy_set_flags(int *ints, int param, int param2)
3993{
3994 int i;
3995
3996 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
3997 if (param)
3998 default_drive_params[i].params.flags |= param2;
3999 else
4000 default_drive_params[i].params.flags &= ~param2;
4001 }
4002 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
4003}
4004
4005static void __init daring(int *ints, int param, int param2)
4006{
4007 int i;
4008
4009 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4010 if (param) {
4011 default_drive_params[i].params.select_delay = 0;
4012 default_drive_params[i].params.flags |=
4013 FD_SILENT_DCL_CLEAR;
4014 } else {
4015 default_drive_params[i].params.select_delay =
4016 2 * HZ / 100;
4017 default_drive_params[i].params.flags &=
4018 ~FD_SILENT_DCL_CLEAR;
4019 }
4020 }
4021 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
4022}
4023
4024static void __init set_cmos(int *ints, int dummy, int dummy2)
4025{
4026 int current_drive = 0;
4027
4028 if (ints[0] != 2) {
4029 DPRINT("wrong number of parameters for CMOS\n");
4030 return;
4031 }
4032 current_drive = ints[1];
4033 if (current_drive < 0 || current_drive >= 8) {
4034 DPRINT("bad drive for set_cmos\n");
4035 return;
4036 }
4037#if N_FDC > 1
4038 if (current_drive >= 4 && !FDC2)
4039 FDC2 = 0x370;
4040#endif
4041 DP->cmos = ints[2];
4042 DPRINT("setting CMOS code to %d\n", ints[2]);
4043}
4044
4045static struct param_table {
4046 const char *name;
4047 void (*fn) (int *ints, int param, int param2);
4048 int *var;
4049 int def_param;
4050 int param2;
4051} config_params[] __initdata = {
4052 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4053 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4054 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4055 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4056 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4057 {"daring", daring, NULL, 1, 0},
4058#if N_FDC > 1
4059 {"two_fdc", NULL, &FDC2, 0x370, 0},
4060 {"one_fdc", NULL, &FDC2, 0, 0},
4061#endif
4062 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4063 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4064 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4065 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4066 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4067 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4068 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4069 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4070 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4071 {"nofifo", NULL, &no_fifo, 0x20, 0},
4072 {"usefifo", NULL, &no_fifo, 0, 0},
4073 {"cmos", set_cmos, NULL, 0, 0},
4074 {"slow", NULL, &slow_floppy, 1, 0},
4075 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4076 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4077 {"L40SX", NULL, &print_unex, 0, 0}
4078
4079 EXTRA_FLOPPY_PARAMS
4080};
4081
4082static int __init floppy_setup(char *str)
4083{
4084 int i;
4085 int param;
4086 int ints[11];
4087
4088 str = get_options(str, ARRAY_SIZE(ints), ints);
4089 if (str) {
4090 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4091 if (strcmp(str, config_params[i].name) == 0) {
4092 if (ints[0])
4093 param = ints[1];
4094 else
4095 param = config_params[i].def_param;
4096 if (config_params[i].fn)
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004097 config_params[i].fn(ints, param,
4098 config_params[i].
4099 param2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100 if (config_params[i].var) {
4101 DPRINT("%s=%d\n", str, param);
4102 *config_params[i].var = param;
4103 }
4104 return 1;
4105 }
4106 }
4107 }
4108 if (str) {
4109 DPRINT("unknown floppy option [%s]\n", str);
4110
4111 DPRINT("allowed options are:");
4112 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004113 pr_cont(" %s", config_params[i].name);
4114 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115 } else
4116 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004117 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118 return 0;
4119}
4120
4121static int have_no_fdc = -ENODEV;
4122
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004123static ssize_t floppy_cmos_show(struct device *dev,
4124 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004125{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004126 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004127 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004128
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004129 drive = p->id;
4130 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004131}
Joe Perches48c8cee2010-03-10 15:20:45 -08004132
4133DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004134
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135static void floppy_device_release(struct device *dev)
4136{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137}
4138
Frans Popc90cd332009-07-25 22:24:54 +02004139static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004140{
4141 int fdc;
4142
4143 for (fdc = 0; fdc < N_FDC; fdc++)
4144 if (FDCS->address != -1)
Joe Perches74f63f42010-03-10 15:20:58 -08004145 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004146
4147 return 0;
4148}
4149
Alexey Dobriyan47145212009-12-14 18:00:08 -08004150static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004151 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004152 .restore = floppy_resume,
4153};
4154
4155static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004156 .driver = {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004157 .name = "floppy",
4158 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004159 },
4160};
4161
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004162static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163
4164static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4165{
4166 int drive = (*part & 3) | ((*part & 0x80) >> 5);
4167 if (drive >= N_DRIVE ||
4168 !(allowed_drive_mask & (1 << drive)) ||
4169 fdc_state[FDC(drive)].version == FDC_NONE)
4170 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004171 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172 return NULL;
4173 *part = 0;
4174 return get_disk(disks[drive]);
4175}
4176
4177static int __init floppy_init(void)
4178{
4179 int i, unit, drive;
4180 int err, dr;
4181
Kumar Gala68e1ee62008-09-22 14:41:31 -07004182#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004183 if (check_legacy_ioport(FDC1))
4184 return -ENODEV;
4185#endif
4186
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187 raw_cmd = NULL;
4188
4189 for (dr = 0; dr < N_DRIVE; dr++) {
4190 disks[dr] = alloc_disk(1);
4191 if (!disks[dr]) {
4192 err = -ENOMEM;
4193 goto out_put_disk;
4194 }
4195
4196 disks[dr]->major = FLOPPY_MAJOR;
4197 disks[dr]->first_minor = TOMINOR(dr);
4198 disks[dr]->fops = &floppy_fops;
4199 sprintf(disks[dr]->disk_name, "fd%d", dr);
4200
4201 init_timer(&motor_off_timer[dr]);
4202 motor_off_timer[dr].data = dr;
4203 motor_off_timer[dr].function = motor_off_callback;
4204 }
4205
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 err = register_blkdev(FLOPPY_MAJOR, "fd");
4207 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004208 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004210 err = platform_driver_register(&floppy_driver);
4211 if (err)
4212 goto out_unreg_blkdev;
4213
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214 floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
4215 if (!floppy_queue) {
4216 err = -ENOMEM;
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004217 goto out_unreg_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218 }
Martin K. Petersen086fa5f2010-02-26 00:20:38 -05004219 blk_queue_max_hw_sectors(floppy_queue, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220
4221 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4222 floppy_find, NULL, NULL);
4223
4224 for (i = 0; i < 256; i++)
4225 if (ITYPE(i))
4226 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4227 else
4228 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4229
Joe Perches73507e62010-03-10 15:21:03 -08004230 reschedule_timeout(MAXTIMEOUT, "floppy init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231 config_types();
4232
4233 for (i = 0; i < N_FDC; i++) {
4234 fdc = i;
Joe Perchesb87c9e02010-03-10 15:20:50 -08004235 memset(FDCS, 0, sizeof(*FDCS));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236 FDCS->dtr = -1;
4237 FDCS->dor = 0x4;
4238#if defined(__sparc__) || defined(__mc68000__)
Joe Perches96534f12010-03-10 15:20:51 -08004239 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240#ifdef __mc68000__
4241 if (MACH_IS_SUN3X)
4242#endif
4243 FDCS->version = FDC_82072A;
4244#endif
4245 }
4246
4247 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248 fdc_state[0].address = FDC1;
4249 if (fdc_state[0].address == -1) {
4250 del_timer(&fd_timeout);
4251 err = -ENODEV;
4252 goto out_unreg_region;
4253 }
4254#if N_FDC > 1
4255 fdc_state[1].address = FDC2;
4256#endif
4257
4258 fdc = 0; /* reset fdc in case of unexpected interrupt */
4259 err = floppy_grab_irq_and_dma();
4260 if (err) {
4261 del_timer(&fd_timeout);
4262 err = -EBUSY;
4263 goto out_unreg_region;
4264 }
4265
4266 /* initialise drive state */
4267 for (drive = 0; drive < N_DRIVE; drive++) {
Joe Perchesb87c9e02010-03-10 15:20:50 -08004268 memset(UDRS, 0, sizeof(*UDRS));
4269 memset(UDRWE, 0, sizeof(*UDRWE));
Joe Perchese0298532010-03-10 15:20:55 -08004270 set_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
4271 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
4272 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273 UDRS->fd_device = -1;
4274 floppy_track_buffer = NULL;
4275 max_buffer_sectors = 0;
4276 }
4277 /*
4278 * Small 10 msec delay to let through any interrupt that
4279 * initialization might have triggered, to not
4280 * confuse detection:
4281 */
4282 msleep(10);
4283
4284 for (i = 0; i < N_FDC; i++) {
4285 fdc = i;
4286 FDCS->driver_version = FD_DRIVER_VERSION;
4287 for (unit = 0; unit < 4; unit++)
4288 FDCS->track[unit] = 0;
4289 if (FDCS->address == -1)
4290 continue;
4291 FDCS->rawcmd = 2;
Joe Perches74f63f42010-03-10 15:20:58 -08004292 if (user_reset_fdc(-1, FD_RESET_ALWAYS, false)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004293 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004294 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295 FDCS->address = -1;
4296 FDCS->version = FDC_NONE;
4297 continue;
4298 }
4299 /* Try to determine the floppy controller type */
4300 FDCS->version = get_fdc_version();
4301 if (FDCS->version == FDC_NONE) {
4302 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004303 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304 FDCS->address = -1;
4305 continue;
4306 }
4307 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4308 can_use_virtual_dma = 0;
4309
4310 have_no_fdc = 0;
4311 /* Not all FDCs seem to be able to handle the version command
4312 * properly, so force a reset for the standard FDC clones,
4313 * to avoid interrupt garbage.
4314 */
Joe Perches74f63f42010-03-10 15:20:58 -08004315 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 }
4317 fdc = 0;
4318 del_timer(&fd_timeout);
4319 current_drive = 0;
Joe Perches29f1c782010-03-10 15:21:00 -08004320 initialized = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321 if (have_no_fdc) {
4322 DPRINT("no floppy controllers found\n");
4323 err = have_no_fdc;
4324 goto out_flush_work;
4325 }
4326
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327 for (drive = 0; drive < N_DRIVE; drive++) {
4328 if (!(allowed_drive_mask & (1 << drive)))
4329 continue;
4330 if (fdc_state[FDC(drive)].version == FDC_NONE)
4331 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004332
4333 floppy_device[drive].name = floppy_device_name;
4334 floppy_device[drive].id = drive;
4335 floppy_device[drive].dev.release = floppy_device_release;
4336
4337 err = platform_device_register(&floppy_device[drive]);
4338 if (err)
4339 goto out_flush_work;
4340
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004341 err = device_create_file(&floppy_device[drive].dev,
4342 &dev_attr_cmos);
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004343 if (err)
4344 goto out_unreg_platform_dev;
4345
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346 /* to be cleaned up... */
4347 disks[drive]->private_data = (void *)(long)drive;
4348 disks[drive]->queue = floppy_queue;
4349 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004350 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351 add_disk(disks[drive]);
4352 }
4353
4354 return 0;
4355
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004356out_unreg_platform_dev:
4357 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358out_flush_work:
4359 flush_scheduled_work();
4360 if (usage_count)
4361 floppy_release_irq_and_dma();
4362out_unreg_region:
4363 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4364 blk_cleanup_queue(floppy_queue);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004365out_unreg_driver:
4366 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367out_unreg_blkdev:
4368 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369out_put_disk:
4370 while (dr--) {
4371 del_timer(&motor_off_timer[dr]);
4372 put_disk(disks[dr]);
4373 }
4374 return err;
4375}
4376
4377static DEFINE_SPINLOCK(floppy_usage_lock);
4378
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004379static const struct io_region {
4380 int offset;
4381 int size;
4382} io_regions[] = {
4383 { 2, 1 },
4384 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4385 { 4, 2 },
4386 /* address + 6 is reserved, and may be taken by IDE.
4387 * Unfortunately, Adaptec doesn't know this :-(, */
4388 { 7, 1 },
4389};
4390
4391static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4392{
4393 while (p != io_regions) {
4394 p--;
4395 release_region(FDCS->address + p->offset, p->size);
4396 }
4397}
4398
4399#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4400
4401static int floppy_request_regions(int fdc)
4402{
4403 const struct io_region *p;
4404
4405 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004406 if (!request_region(FDCS->address + p->offset,
4407 p->size, "floppy")) {
4408 DPRINT("Floppy io-port 0x%04lx in use\n",
4409 FDCS->address + p->offset);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004410 floppy_release_allocated_regions(fdc, p);
4411 return -EBUSY;
4412 }
4413 }
4414 return 0;
4415}
4416
4417static void floppy_release_regions(int fdc)
4418{
4419 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4420}
4421
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422static int floppy_grab_irq_and_dma(void)
4423{
4424 unsigned long flags;
4425
4426 spin_lock_irqsave(&floppy_usage_lock, flags);
4427 if (usage_count++) {
4428 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4429 return 0;
4430 }
4431 spin_unlock_irqrestore(&floppy_usage_lock, flags);
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004432
4433 /*
4434 * We might have scheduled a free_irq(), wait it to
4435 * drain first:
4436 */
4437 flush_scheduled_work();
4438
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439 if (fd_request_irq()) {
4440 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4441 FLOPPY_IRQ);
4442 spin_lock_irqsave(&floppy_usage_lock, flags);
4443 usage_count--;
4444 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4445 return -1;
4446 }
4447 if (fd_request_dma()) {
4448 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4449 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004450 if (can_use_virtual_dma & 2)
4451 use_virtual_dma = can_use_virtual_dma = 1;
4452 if (!(can_use_virtual_dma & 1)) {
4453 fd_free_irq();
4454 spin_lock_irqsave(&floppy_usage_lock, flags);
4455 usage_count--;
4456 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4457 return -1;
4458 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459 }
4460
4461 for (fdc = 0; fdc < N_FDC; fdc++) {
4462 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004463 if (floppy_request_regions(fdc))
4464 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465 }
4466 }
4467 for (fdc = 0; fdc < N_FDC; fdc++) {
4468 if (FDCS->address != -1) {
4469 reset_fdc_info(1);
4470 fd_outb(FDCS->dor, FD_DOR);
4471 }
4472 }
4473 fdc = 0;
4474 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4475
4476 for (fdc = 0; fdc < N_FDC; fdc++)
4477 if (FDCS->address != -1)
4478 fd_outb(FDCS->dor, FD_DOR);
4479 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004480 * The driver will try and free resources and relies on us
4481 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 */
4483 fdc = 0;
4484 irqdma_allocated = 1;
4485 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004486cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 fd_free_irq();
4488 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004489 while (--fdc >= 0)
4490 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 spin_lock_irqsave(&floppy_usage_lock, flags);
4492 usage_count--;
4493 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4494 return -1;
4495}
4496
4497static void floppy_release_irq_and_dma(void)
4498{
4499 int old_fdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500#ifndef __sparc__
4501 int drive;
4502#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 long tmpsize;
4504 unsigned long tmpaddr;
4505 unsigned long flags;
4506
4507 spin_lock_irqsave(&floppy_usage_lock, flags);
4508 if (--usage_count) {
4509 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4510 return;
4511 }
4512 spin_unlock_irqrestore(&floppy_usage_lock, flags);
4513 if (irqdma_allocated) {
4514 fd_disable_dma();
4515 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004516 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517 irqdma_allocated = 0;
4518 }
4519 set_dor(0, ~0, 8);
4520#if N_FDC > 1
4521 set_dor(1, ~8, 0);
4522#endif
4523 floppy_enable_hlt();
4524
4525 if (floppy_track_buffer && max_buffer_sectors) {
4526 tmpsize = max_buffer_sectors * 1024;
4527 tmpaddr = (unsigned long)floppy_track_buffer;
4528 floppy_track_buffer = NULL;
4529 max_buffer_sectors = 0;
4530 buffer_min = buffer_max = -1;
4531 fd_dma_mem_free(tmpaddr, tmpsize);
4532 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533#ifndef __sparc__
4534 for (drive = 0; drive < N_FDC * 4; drive++)
4535 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004536 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537#endif
4538
4539 if (timer_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004540 pr_info("floppy timer still active:%s\n", timeout_message);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004542 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004543 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004544 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545 old_fdc = fdc;
4546 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004547 if (FDCS->address != -1)
4548 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549 fdc = old_fdc;
4550}
4551
4552#ifdef MODULE
4553
4554static char *floppy;
4555
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556static void __init parse_floppy_cfg_string(char *cfg)
4557{
4558 char *ptr;
4559
4560 while (*cfg) {
Joe Perchesbb57f0c62010-03-10 15:20:50 -08004561 ptr = cfg;
4562 while (*cfg && *cfg != ' ' && *cfg != '\t')
4563 cfg++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 if (*cfg) {
4565 *cfg = '\0';
4566 cfg++;
4567 }
4568 if (*ptr)
4569 floppy_setup(ptr);
4570 }
4571}
4572
Jon Schindler7afea3b2008-04-29 00:59:21 -07004573static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574{
4575 if (floppy)
4576 parse_floppy_cfg_string(floppy);
4577 return floppy_init();
4578}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004579module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580
Jon Schindler7afea3b2008-04-29 00:59:21 -07004581static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582{
4583 int drive;
4584
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4586 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004587 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588
4589 for (drive = 0; drive < N_DRIVE; drive++) {
4590 del_timer_sync(&motor_off_timer[drive]);
4591
4592 if ((allowed_drive_mask & (1 << drive)) &&
4593 fdc_state[FDC(drive)].version != FDC_NONE) {
4594 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004595 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4596 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597 }
4598 put_disk(disks[drive]);
4599 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600
4601 del_timer_sync(&fd_timeout);
4602 del_timer_sync(&fd_timer);
4603 blk_cleanup_queue(floppy_queue);
4604
4605 if (usage_count)
4606 floppy_release_irq_and_dma();
4607
4608 /* eject disk, if any */
4609 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610}
Joe Perches48c8cee2010-03-10 15:20:45 -08004611
Jon Schindler7afea3b2008-04-29 00:59:21 -07004612module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613
4614module_param(floppy, charp, 0);
4615module_param(FLOPPY_IRQ, int, 0);
4616module_param(FLOPPY_DMA, int, 0);
4617MODULE_AUTHOR("Alain L. Knaff");
4618MODULE_SUPPORTED_DEVICE("fd");
4619MODULE_LICENSE("GPL");
4620
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004621/* This doesn't actually get used other than for module information */
4622static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004623 {"PNP0700", 0},
4624 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004625};
Joe Perches48c8cee2010-03-10 15:20:45 -08004626
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004627MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4628
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629#else
4630
4631__setup("floppy=", floppy_setup);
4632module_init(floppy_init)
4633#endif
4634
4635MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);