blob: 82c30f9f81ca29a101d342e8d8554e98541fa3a2 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517/* Errors during formatting are counted here. */
518static int format_errors;
519
520/* Format request descriptor. */
521static struct format_descr format_req;
522
523/*
524 * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
525 * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
526 * H is head unload time (1=16ms, 2=32ms, etc)
527 */
528
529/*
530 * Track buffer
531 * Because these are written to by the DMA controller, they must
532 * not contain a 64k byte boundary crossing, or data will be
533 * corrupted/lost.
534 */
535static char *floppy_track_buffer;
536static int max_buffer_sectors;
537
538static int *errors;
Jesper Juhl06f748c2007-10-16 23:30:57 -0700539typedef void (*done_f)(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540static struct cont_t {
Joe Perches48c8cee2010-03-10 15:20:45 -0800541 void (*interrupt)(void);
542 /* this is called after the interrupt of the
543 * main command */
Jesper Juhl06f748c2007-10-16 23:30:57 -0700544 void (*redo)(void); /* this is called to retry the operation */
545 void (*error)(void); /* this is called to tally an error */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 done_f done; /* this is called to say if the operation has
547 * succeeded/failed */
548} *cont;
549
550static void floppy_ready(void);
551static void floppy_start(void);
552static void process_fd_request(void);
553static void recalibrate_floppy(void);
554static void floppy_shutdown(unsigned long);
555
Philippe De Muyter5a74db02009-02-18 14:48:36 -0800556static int floppy_request_regions(int);
557static void floppy_release_regions(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558static int floppy_grab_irq_and_dma(void);
559static void floppy_release_irq_and_dma(void);
560
561/*
562 * The "reset" variable should be tested whenever an interrupt is scheduled,
563 * after the commands have been sent. This is to ensure that the driver doesn't
564 * get wedged when the interrupt doesn't come because of a failed command.
565 * reset doesn't need to be tested before sending commands, because
566 * output_byte is automatically disabled when reset is set.
567 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568static void reset_fdc(void);
569
570/*
571 * These are global variables, as that's the easiest way to give
572 * information to interrupts. They are the data used for the current
573 * request.
574 */
Joe Perches48c8cee2010-03-10 15:20:45 -0800575#define NO_TRACK -1
576#define NEED_1_RECAL -2
577#define NEED_2_RECAL -3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
Stephen Hemminger575cfc62010-06-15 13:21:11 +0200579static atomic_t usage_count = ATOMIC_INIT(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
581/* buffer related variables */
582static int buffer_track = -1;
583static int buffer_drive = -1;
584static int buffer_min = -1;
585static int buffer_max = -1;
586
587/* fdc related variables, should end up in a struct */
588static struct floppy_fdc_state fdc_state[N_FDC];
589static int fdc; /* current fdc */
590
591static struct floppy_struct *_floppy = floppy_type;
592static unsigned char current_drive;
593static long current_count_sectors;
594static unsigned char fsector_t; /* sector in track */
595static unsigned char in_sector_offset; /* offset within physical sector,
596 * expressed in units of 512 bytes */
597
598#ifndef fd_eject
599static inline int fd_eject(int drive)
600{
601 return -EINVAL;
602}
603#endif
604
605/*
606 * Debugging
607 * =========
608 */
609#ifdef DEBUGT
610static long unsigned debugtimer;
611
612static inline void set_debugt(void)
613{
614 debugtimer = jiffies;
615}
616
Joe Perchesded28632010-03-10 15:21:09 -0800617static inline void debugt(const char *func, const char *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618{
619 if (DP->flags & DEBUGT)
Joe Perchesded28632010-03-10 15:21:09 -0800620 pr_info("%s:%s dtime=%lu\n", func, msg, jiffies - debugtimer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621}
622#else
623static inline void set_debugt(void) { }
Joe Perchesded28632010-03-10 15:21:09 -0800624static inline void debugt(const char *func, const char *msg) { }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625#endif /* DEBUGT */
626
Joe Perchesa0a52d62010-03-10 15:20:52 -0800627typedef void (*timeout_fn)(unsigned long);
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700628static DEFINE_TIMER(fd_timeout, floppy_shutdown, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
630static const char *timeout_message;
631
Joe Perches275176b2010-03-10 15:21:06 -0800632static void is_alive(const char *func, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633{
634 /* this routine checks whether the floppy driver is "alive" */
Joe Perchesc5297302010-03-10 15:20:58 -0800635 if (test_bit(0, &fdc_busy) && command_status < 2 &&
636 !timer_pending(&fd_timeout)) {
Joe Perches275176b2010-03-10 15:21:06 -0800637 DPRINT("%s: timeout handler died. %s\n", func, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 }
639}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
Joe Perches48c8cee2010-03-10 15:20:45 -0800641static void (*do_floppy)(void) = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643#define OLOGSIZE 20
644
Joe Perches48c8cee2010-03-10 15:20:45 -0800645static void (*lasthandler)(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646static unsigned long interruptjiffies;
647static unsigned long resultjiffies;
648static int resultsize;
649static unsigned long lastredo;
650
651static struct output_log {
652 unsigned char data;
653 unsigned char status;
654 unsigned long jiffies;
655} output_log[OLOGSIZE];
656
657static int output_log_pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
659#define current_reqD -1
660#define MAXTIMEOUT -2
661
Joe Perches73507e62010-03-10 15:21:03 -0800662static void __reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663{
664 if (drive == current_reqD)
665 drive = current_drive;
666 del_timer(&fd_timeout);
Eric Sesterhenn / Snakebyte4acb3e22007-05-23 13:58:15 -0700667 if (drive < 0 || drive >= N_DRIVE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 fd_timeout.expires = jiffies + 20UL * HZ;
669 drive = 0;
670 } else
671 fd_timeout.expires = jiffies + UDP->timeout;
672 add_timer(&fd_timeout);
Joe Perchesa81ee542010-03-10 15:20:46 -0800673 if (UDP->flags & FD_DEBUG)
Joe Perches73507e62010-03-10 15:21:03 -0800674 DPRINT("reschedule timeout %s\n", message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 timeout_message = message;
676}
677
Joe Perches73507e62010-03-10 15:21:03 -0800678static void reschedule_timeout(int drive, const char *message)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679{
680 unsigned long flags;
681
682 spin_lock_irqsave(&floppy_lock, flags);
Joe Perches73507e62010-03-10 15:21:03 -0800683 __reschedule_timeout(drive, message);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 spin_unlock_irqrestore(&floppy_lock, flags);
685}
686
Joe Perches48c8cee2010-03-10 15:20:45 -0800687#define INFBOUND(a, b) (a) = max_t(int, a, b)
688#define SUPBOUND(a, b) (a) = min_t(int, a, b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
690/*
691 * Bottom half floppy driver.
692 * ==========================
693 *
694 * This part of the file contains the code talking directly to the hardware,
695 * and also the main service loop (seek-configure-spinup-command)
696 */
697
698/*
699 * disk change.
700 * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
701 * and the last_checked date.
702 *
703 * last_checked is the date of the last check which showed 'no disk change'
704 * FD_DISK_CHANGE is set under two conditions:
705 * 1. The floppy has been changed after some i/o to that floppy already
706 * took place.
707 * 2. No floppy disk is in the drive. This is done in order to ensure that
708 * requests are quickly flushed in case there is no disk in the drive. It
709 * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
710 * the drive.
711 *
712 * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
713 * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
714 * each seek. If a disk is present, the disk change line should also be
715 * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
716 * change line is set, this means either that no disk is in the drive, or
717 * that it has been removed since the last seek.
718 *
719 * This means that we really have a third possibility too:
720 * The floppy has been changed after the last seek.
721 */
722
723static int disk_change(int drive)
724{
725 int fdc = FDC(drive);
Jesper Juhl06f748c2007-10-16 23:30:57 -0700726
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -0800727 if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 DPRINT("WARNING disk change called early\n");
729 if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
730 (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
731 DPRINT("probing disk change on unselected drive\n");
732 DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
733 (unsigned int)FDCS->dor);
734 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
Joe Perches87f530d2010-03-10 15:20:54 -0800736 debug_dcl(UDP->flags,
737 "checking disk change line for drive %d\n", drive);
738 debug_dcl(UDP->flags, "jiffies=%lu\n", jiffies);
739 debug_dcl(UDP->flags, "disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
740 debug_dcl(UDP->flags, "flags=%lx\n", UDRS->flags);
741
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 if (UDP->flags & FD_BROKEN_DCL)
Joe Perchese0298532010-03-10 15:20:55 -0800743 return test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
Joe Perchese0298532010-03-10 15:20:55 -0800745 set_bit(FD_VERIFY_BIT, &UDRS->flags);
746 /* verify write protection */
747
748 if (UDRS->maxblock) /* mark it changed */
749 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
751 /* invalidate its geometry */
752 if (UDRS->keep_data >= 0) {
753 if ((UDP->flags & FTD_MSG) &&
754 current_type[drive] != NULL)
Joe Perches891eda82010-03-10 15:21:05 -0800755 DPRINT("Disk type is undefined after disk change\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 current_type[drive] = NULL;
757 floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
758 }
759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 return 1;
761 } else {
762 UDRS->last_checked = jiffies;
Joe Perchese0298532010-03-10 15:20:55 -0800763 clear_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 }
765 return 0;
766}
767
768static inline int is_selected(int dor, int unit)
769{
770 return ((dor & (0x10 << unit)) && (dor & 3) == unit);
771}
772
Joe Perches57584c52010-03-10 15:21:00 -0800773static bool is_ready_state(int status)
774{
775 int state = status & (STATUS_READY | STATUS_DIR | STATUS_DMA);
776 return state == STATUS_READY;
777}
778
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779static int set_dor(int fdc, char mask, char data)
780{
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700781 unsigned char unit;
782 unsigned char drive;
783 unsigned char newdor;
784 unsigned char olddor;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
786 if (FDCS->address == -1)
787 return -1;
788
789 olddor = FDCS->dor;
790 newdor = (olddor & mask) | data;
791 if (newdor != olddor) {
792 unit = olddor & 0x3;
793 if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
794 drive = REVDRIVE(fdc, unit);
Joe Perches87f530d2010-03-10 15:20:54 -0800795 debug_dcl(UDP->flags,
796 "calling disk change from set_dor\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 disk_change(drive);
798 }
799 FDCS->dor = newdor;
800 fd_outb(newdor, FD_DOR);
801
802 unit = newdor & 0x3;
803 if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
804 drive = REVDRIVE(fdc, unit);
805 UDRS->select_date = jiffies;
806 }
807 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 return olddor;
809}
810
811static void twaddle(void)
812{
813 if (DP->select_delay)
814 return;
815 fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
816 fd_outb(FDCS->dor, FD_DOR);
817 DRS->select_date = jiffies;
818}
819
Joe Perches57584c52010-03-10 15:21:00 -0800820/*
821 * Reset all driver information about the current fdc.
822 * This is needed after a reset, and after a raw command.
823 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824static void reset_fdc_info(int mode)
825{
826 int drive;
827
828 FDCS->spec1 = FDCS->spec2 = -1;
829 FDCS->need_configure = 1;
830 FDCS->perp_mode = 1;
831 FDCS->rawcmd = 0;
832 for (drive = 0; drive < N_DRIVE; drive++)
833 if (FDC(drive) == fdc && (mode || UDRS->track != NEED_1_RECAL))
834 UDRS->track = NEED_2_RECAL;
835}
836
837/* selects the fdc and drive, and enables the fdc's input/dma. */
838static void set_fdc(int drive)
839{
840 if (drive >= 0 && drive < N_DRIVE) {
841 fdc = FDC(drive);
842 current_drive = drive;
843 }
844 if (fdc != 1 && fdc != 0) {
Joe Perchesb46df352010-03-10 15:20:46 -0800845 pr_info("bad fdc value\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 return;
847 }
848 set_dor(fdc, ~0, 8);
849#if N_FDC > 1
850 set_dor(1 - fdc, ~8, 0);
851#endif
852 if (FDCS->rawcmd == 2)
853 reset_fdc_info(1);
854 if (fd_inb(FD_STATUS) != STATUS_READY)
855 FDCS->reset = 1;
856}
857
858/* locks the driver */
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200859static int lock_fdc(int drive, bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860{
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200861 if (WARN(atomic_read(&usage_count) == 0,
862 "Trying to lock fdc while usage count=0\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864
Stephen Hemmingerb862f262010-06-15 13:21:11 +0200865 if (wait_event_interruptible(fdc_wait, !test_and_set_bit(0, &fdc_busy)))
866 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 command_status = FD_COMMAND_NONE;
869
Joe Perches73507e62010-03-10 15:21:03 -0800870 __reschedule_timeout(drive, "lock fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 set_fdc(drive);
872 return 0;
873}
874
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875/* unlocks the driver */
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +0200876static void unlock_fdc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877{
878 unsigned long flags;
879
880 raw_cmd = NULL;
881 if (!test_bit(0, &fdc_busy))
882 DPRINT("FDC access conflict!\n");
883
884 if (do_floppy)
Joe Perches1ebddd82010-03-10 15:21:07 -0800885 DPRINT("device interrupt still active at FDC release: %pf!\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 do_floppy);
887 command_status = FD_COMMAND_NONE;
888 spin_lock_irqsave(&floppy_lock, flags);
889 del_timer(&fd_timeout);
890 cont = NULL;
891 clear_bit(0, &fdc_busy);
Tejun Heo9934c8c2009-05-08 11:54:16 +0900892 if (current_req || blk_peek_request(floppy_queue))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 do_fd_request(floppy_queue);
894 spin_unlock_irqrestore(&floppy_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 wake_up(&fdc_wait);
896}
897
898/* switches the motor off after a given timeout */
899static void motor_off_callback(unsigned long nr)
900{
901 unsigned char mask = ~(0x10 << UNIT(nr));
902
903 set_dor(FDC(nr), mask, 0);
904}
905
906/* schedules motor off */
907static void floppy_off(unsigned int drive)
908{
909 unsigned long volatile delta;
Jesper Juhlfdc1ca82007-10-16 23:30:58 -0700910 int fdc = FDC(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911
912 if (!(FDCS->dor & (0x10 << UNIT(drive))))
913 return;
914
915 del_timer(motor_off_timer + drive);
916
917 /* make spindle stop in a position which minimizes spinup time
918 * next time */
919 if (UDP->rps) {
920 delta = jiffies - UDRS->first_read_date + HZ -
921 UDP->spindown_offset;
922 delta = ((delta * UDP->rps) % HZ) / UDP->rps;
923 motor_off_timer[drive].expires =
924 jiffies + UDP->spindown - delta;
925 }
926 add_timer(motor_off_timer + drive);
927}
928
929/*
930 * cycle through all N_DRIVE floppy drives, for disk change testing.
931 * stopping at current drive. This is done before any long operation, to
932 * be sure to have up to date disk change information.
933 */
934static void scandrives(void)
935{
Jesper Juhl06f748c2007-10-16 23:30:57 -0700936 int i;
937 int drive;
938 int saved_drive;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
940 if (DP->select_delay)
941 return;
942
943 saved_drive = current_drive;
944 for (i = 0; i < N_DRIVE; i++) {
945 drive = (saved_drive + i + 1) % N_DRIVE;
946 if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
947 continue; /* skip closed drives */
948 set_fdc(drive);
949 if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
950 (0x10 << UNIT(drive))))
951 /* switch the motor off again, if it was off to
952 * begin with */
953 set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
954 }
955 set_fdc(saved_drive);
956}
957
958static void empty(void)
959{
960}
961
David Howells65f27f32006-11-22 14:55:48 +0000962static DECLARE_WORK(floppy_work, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963
Joe Perches48c8cee2010-03-10 15:20:45 -0800964static void schedule_bh(void (*handler)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965{
David Howells65f27f32006-11-22 14:55:48 +0000966 PREPARE_WORK(&floppy_work, (work_func_t)handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 schedule_work(&floppy_work);
968}
969
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700970static DEFINE_TIMER(fd_timer, NULL, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
972static void cancel_activity(void)
973{
974 unsigned long flags;
975
976 spin_lock_irqsave(&floppy_lock, flags);
977 do_floppy = NULL;
David Howells65f27f32006-11-22 14:55:48 +0000978 PREPARE_WORK(&floppy_work, (work_func_t)empty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 del_timer(&fd_timer);
980 spin_unlock_irqrestore(&floppy_lock, flags);
981}
982
983/* this function makes sure that the disk stays in the drive during the
984 * transfer */
985static void fd_watchdog(void)
986{
Joe Perches87f530d2010-03-10 15:20:54 -0800987 debug_dcl(DP->flags, "calling disk change from watchdog\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
989 if (disk_change(current_drive)) {
990 DPRINT("disk removed during i/o\n");
991 cancel_activity();
992 cont->done(0);
993 reset_fdc();
994 } else {
995 del_timer(&fd_timer);
Joe Perchesa0a52d62010-03-10 15:20:52 -0800996 fd_timer.function = (timeout_fn)fd_watchdog;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 fd_timer.expires = jiffies + HZ / 10;
998 add_timer(&fd_timer);
999 }
1000}
1001
1002static void main_command_interrupt(void)
1003{
1004 del_timer(&fd_timer);
1005 cont->interrupt();
1006}
1007
1008/* waits for a delay (spinup or select) to pass */
1009static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
1010{
1011 if (FDCS->reset) {
1012 reset_fdc(); /* do the reset during sleep to win time
1013 * if we don't need to sleep, it's a good
1014 * occasion anyways */
1015 return 1;
1016 }
1017
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001018 if (time_before(jiffies, delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 del_timer(&fd_timer);
1020 fd_timer.function = function;
1021 fd_timer.expires = delay;
1022 add_timer(&fd_timer);
1023 return 1;
1024 }
1025 return 0;
1026}
1027
1028static DEFINE_SPINLOCK(floppy_hlt_lock);
1029static int hlt_disabled;
1030static void floppy_disable_hlt(void)
1031{
1032 unsigned long flags;
1033
1034 spin_lock_irqsave(&floppy_hlt_lock, flags);
1035 if (!hlt_disabled) {
1036 hlt_disabled = 1;
1037#ifdef HAVE_DISABLE_HLT
1038 disable_hlt();
1039#endif
1040 }
1041 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1042}
1043
1044static void floppy_enable_hlt(void)
1045{
1046 unsigned long flags;
1047
1048 spin_lock_irqsave(&floppy_hlt_lock, flags);
1049 if (hlt_disabled) {
1050 hlt_disabled = 0;
1051#ifdef HAVE_DISABLE_HLT
1052 enable_hlt();
1053#endif
1054 }
1055 spin_unlock_irqrestore(&floppy_hlt_lock, flags);
1056}
1057
1058static void setup_DMA(void)
1059{
1060 unsigned long f;
1061
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 if (raw_cmd->length == 0) {
1063 int i;
1064
Joe Perchesb46df352010-03-10 15:20:46 -08001065 pr_info("zero dma transfer size:");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 for (i = 0; i < raw_cmd->cmd_count; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001067 pr_cont("%x,", raw_cmd->cmd[i]);
1068 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 cont->done(0);
1070 FDCS->reset = 1;
1071 return;
1072 }
1073 if (((unsigned long)raw_cmd->kernel_data) % 512) {
Joe Perchesb46df352010-03-10 15:20:46 -08001074 pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 cont->done(0);
1076 FDCS->reset = 1;
1077 return;
1078 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 f = claim_dma_lock();
1080 fd_disable_dma();
1081#ifdef fd_dma_setup
1082 if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1083 (raw_cmd->flags & FD_RAW_READ) ?
1084 DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
1085 release_dma_lock(f);
1086 cont->done(0);
1087 FDCS->reset = 1;
1088 return;
1089 }
1090 release_dma_lock(f);
1091#else
1092 fd_clear_dma_ff();
1093 fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1094 fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1095 DMA_MODE_READ : DMA_MODE_WRITE);
1096 fd_set_dma_addr(raw_cmd->kernel_data);
1097 fd_set_dma_count(raw_cmd->length);
1098 virtual_dma_port = FDCS->address;
1099 fd_enable_dma();
1100 release_dma_lock(f);
1101#endif
1102 floppy_disable_hlt();
1103}
1104
1105static void show_floppy(void);
1106
1107/* waits until the fdc becomes ready */
1108static int wait_til_ready(void)
1109{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001110 int status;
1111 int counter;
1112
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 if (FDCS->reset)
1114 return -1;
1115 for (counter = 0; counter < 10000; counter++) {
1116 status = fd_inb(FD_STATUS);
1117 if (status & STATUS_READY)
1118 return status;
1119 }
Joe Perches29f1c782010-03-10 15:21:00 -08001120 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1122 show_floppy();
1123 }
1124 FDCS->reset = 1;
1125 return -1;
1126}
1127
1128/* sends a command byte to the fdc */
1129static int output_byte(char byte)
1130{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001131 int status = wait_til_ready();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001133 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001135
1136 if (is_ready_state(status)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 fd_outb(byte, FD_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 output_log[output_log_pos].data = byte;
1139 output_log[output_log_pos].status = status;
1140 output_log[output_log_pos].jiffies = jiffies;
1141 output_log_pos = (output_log_pos + 1) % OLOGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 return 0;
1143 }
1144 FDCS->reset = 1;
Joe Perches29f1c782010-03-10 15:21:00 -08001145 if (initialized) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1147 byte, fdc, status);
1148 show_floppy();
1149 }
1150 return -1;
1151}
1152
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153/* gets the response from the fdc */
1154static int result(void)
1155{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001156 int i;
1157 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158
1159 for (i = 0; i < MAX_REPLIES; i++) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001160 status = wait_til_ready();
1161 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 break;
1163 status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1164 if ((status & ~STATUS_BUSY) == STATUS_READY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 resultjiffies = jiffies;
1166 resultsize = i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 return i;
1168 }
1169 if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1170 reply_buffer[i] = fd_inb(FD_DATA);
1171 else
1172 break;
1173 }
Joe Perches29f1c782010-03-10 15:21:00 -08001174 if (initialized) {
1175 DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1176 fdc, status, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 show_floppy();
1178 }
1179 FDCS->reset = 1;
1180 return -1;
1181}
1182
1183#define MORE_OUTPUT -2
1184/* does the fdc need more output? */
1185static int need_more_output(void)
1186{
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001187 int status = wait_til_ready();
Jesper Juhl06f748c2007-10-16 23:30:57 -07001188
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001189 if (status < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 return -1;
Joe Perches57584c52010-03-10 15:21:00 -08001191
1192 if (is_ready_state(status))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 return MORE_OUTPUT;
Joe Perches57584c52010-03-10 15:21:00 -08001194
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 return result();
1196}
1197
1198/* Set perpendicular mode as required, based on data rate, if supported.
1199 * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1200 */
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02001201static void perpendicular_mode(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202{
1203 unsigned char perp_mode;
1204
1205 if (raw_cmd->rate & 0x40) {
1206 switch (raw_cmd->rate & 3) {
1207 case 0:
1208 perp_mode = 2;
1209 break;
1210 case 3:
1211 perp_mode = 3;
1212 break;
1213 default:
1214 DPRINT("Invalid data rate for perpendicular mode!\n");
1215 cont->done(0);
Joe Perchesbb57f0c2010-03-10 15:20:50 -08001216 FDCS->reset = 1;
1217 /*
1218 * convenient way to return to
1219 * redo without too much hassle
1220 * (deep stack et al.)
1221 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 return;
1223 }
1224 } else
1225 perp_mode = 0;
1226
1227 if (FDCS->perp_mode == perp_mode)
1228 return;
1229 if (FDCS->version >= FDC_82077_ORIG) {
1230 output_byte(FD_PERPENDICULAR);
1231 output_byte(perp_mode);
1232 FDCS->perp_mode = perp_mode;
1233 } else if (perp_mode) {
1234 DPRINT("perpendicular mode not supported by this FDC.\n");
1235 }
1236} /* perpendicular_mode */
1237
1238static int fifo_depth = 0xa;
1239static int no_fifo;
1240
1241static int fdc_configure(void)
1242{
1243 /* Turn on FIFO */
1244 output_byte(FD_CONFIGURE);
1245 if (need_more_output() != MORE_OUTPUT)
1246 return 0;
1247 output_byte(0);
1248 output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1249 output_byte(0); /* pre-compensation from track
1250 0 upwards */
1251 return 1;
1252}
1253
1254#define NOMINAL_DTR 500
1255
1256/* Issue a "SPECIFY" command to set the step rate time, head unload time,
1257 * head load time, and DMA disable flag to values needed by floppy.
1258 *
1259 * The value "dtr" is the data transfer rate in Kbps. It is needed
1260 * to account for the data rate-based scaling done by the 82072 and 82077
1261 * FDC types. This parameter is ignored for other types of FDCs (i.e.
1262 * 8272a).
1263 *
1264 * Note that changing the data transfer rate has a (probably deleterious)
1265 * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1266 * fdc_specify is called again after each data transfer rate
1267 * change.
1268 *
1269 * srt: 1000 to 16000 in microseconds
1270 * hut: 16 to 240 milliseconds
1271 * hlt: 2 to 254 milliseconds
1272 *
1273 * These values are rounded up to the next highest available delay time.
1274 */
1275static void fdc_specify(void)
1276{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001277 unsigned char spec1;
1278 unsigned char spec2;
1279 unsigned long srt;
1280 unsigned long hlt;
1281 unsigned long hut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 unsigned long dtr = NOMINAL_DTR;
1283 unsigned long scale_dtr = NOMINAL_DTR;
1284 int hlt_max_code = 0x7f;
1285 int hut_max_code = 0xf;
1286
1287 if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
1288 fdc_configure();
1289 FDCS->need_configure = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 }
1291
1292 switch (raw_cmd->rate & 0x03) {
1293 case 3:
1294 dtr = 1000;
1295 break;
1296 case 1:
1297 dtr = 300;
1298 if (FDCS->version >= FDC_82078) {
1299 /* chose the default rate table, not the one
1300 * where 1 = 2 Mbps */
1301 output_byte(FD_DRIVESPEC);
1302 if (need_more_output() == MORE_OUTPUT) {
1303 output_byte(UNIT(current_drive));
1304 output_byte(0xc0);
1305 }
1306 }
1307 break;
1308 case 2:
1309 dtr = 250;
1310 break;
1311 }
1312
1313 if (FDCS->version >= FDC_82072) {
1314 scale_dtr = dtr;
1315 hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1316 hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1317 }
1318
1319 /* Convert step rate from microseconds to milliseconds and 4 bits */
Julia Lawall061837b2008-09-22 14:57:16 -07001320 srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
Joe Perchesa81ee542010-03-10 15:20:46 -08001321 if (slow_floppy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 srt = srt / 4;
Joe Perchesa81ee542010-03-10 15:20:46 -08001323
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 SUPBOUND(srt, 0xf);
1325 INFBOUND(srt, 0);
1326
Julia Lawall061837b2008-09-22 14:57:16 -07001327 hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 if (hlt < 0x01)
1329 hlt = 0x01;
1330 else if (hlt > 0x7f)
1331 hlt = hlt_max_code;
1332
Julia Lawall061837b2008-09-22 14:57:16 -07001333 hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 if (hut < 0x1)
1335 hut = 0x1;
1336 else if (hut > 0xf)
1337 hut = hut_max_code;
1338
1339 spec1 = (srt << 4) | hut;
1340 spec2 = (hlt << 1) | (use_virtual_dma & 1);
1341
1342 /* If these parameters did not change, just return with success */
1343 if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
1344 /* Go ahead and set spec1 and spec2 */
1345 output_byte(FD_SPECIFY);
1346 output_byte(FDCS->spec1 = spec1);
1347 output_byte(FDCS->spec2 = spec2);
1348 }
1349} /* fdc_specify */
1350
1351/* Set the FDC's data transfer rate on behalf of the specified drive.
1352 * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1353 * of the specify command (i.e. using the fdc_specify function).
1354 */
1355static int fdc_dtr(void)
1356{
1357 /* If data rate not already set to desired value, set it. */
1358 if ((raw_cmd->rate & 3) == FDCS->dtr)
1359 return 0;
1360
1361 /* Set dtr */
1362 fd_outb(raw_cmd->rate & 3, FD_DCR);
1363
1364 /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1365 * need a stabilization period of several milliseconds to be
1366 * enforced after data rate changes before R/W operations.
1367 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1368 */
1369 FDCS->dtr = raw_cmd->rate & 3;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001370 return fd_wait_for_completion(jiffies + 2UL * HZ / 100,
1371 (timeout_fn)floppy_ready);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372} /* fdc_dtr */
1373
1374static void tell_sector(void)
1375{
Joe Perchesb46df352010-03-10 15:20:46 -08001376 pr_cont(": track %d, head %d, sector %d, size %d",
1377 R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378} /* tell_sector */
1379
Joe Perchesb46df352010-03-10 15:20:46 -08001380static void print_errors(void)
1381{
1382 DPRINT("");
1383 if (ST0 & ST0_ECE) {
1384 pr_cont("Recalibrate failed!");
1385 } else if (ST2 & ST2_CRC) {
1386 pr_cont("data CRC error");
1387 tell_sector();
1388 } else if (ST1 & ST1_CRC) {
1389 pr_cont("CRC error");
1390 tell_sector();
1391 } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
1392 (ST2 & ST2_MAM)) {
1393 if (!probing) {
1394 pr_cont("sector not found");
1395 tell_sector();
1396 } else
1397 pr_cont("probe failed...");
1398 } else if (ST2 & ST2_WC) { /* seek error */
1399 pr_cont("wrong cylinder");
1400 } else if (ST2 & ST2_BC) { /* cylinder marked as bad */
1401 pr_cont("bad cylinder");
1402 } else {
1403 pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1404 ST0, ST1, ST2);
1405 tell_sector();
1406 }
1407 pr_cont("\n");
1408}
1409
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410/*
1411 * OK, this error interpreting routine is called after a
1412 * DMA read/write has succeeded
1413 * or failed, so we check the results, and copy any buffers.
1414 * hhb: Added better error reporting.
1415 * ak: Made this into a separate routine.
1416 */
1417static int interpret_errors(void)
1418{
1419 char bad;
1420
1421 if (inr != 7) {
Joe Perches891eda82010-03-10 15:21:05 -08001422 DPRINT("-- FDC reply error\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 FDCS->reset = 1;
1424 return 1;
1425 }
1426
1427 /* check IC to find cause of interrupt */
1428 switch (ST0 & ST0_INTR) {
1429 case 0x40: /* error occurred during command execution */
1430 if (ST1 & ST1_EOC)
1431 return 0; /* occurs with pseudo-DMA */
1432 bad = 1;
1433 if (ST1 & ST1_WP) {
1434 DPRINT("Drive is write protected\n");
Joe Perchese0298532010-03-10 15:20:55 -08001435 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 cont->done(0);
1437 bad = 2;
1438 } else if (ST1 & ST1_ND) {
Joe Perchese0298532010-03-10 15:20:55 -08001439 set_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 } else if (ST1 & ST1_OR) {
1441 if (DP->flags & FTD_MSG)
1442 DPRINT("Over/Underrun - retrying\n");
1443 bad = 0;
1444 } else if (*errors >= DP->max_errors.reporting) {
Joe Perchesb46df352010-03-10 15:20:46 -08001445 print_errors();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 }
1447 if (ST2 & ST2_WC || ST2 & ST2_BC)
1448 /* wrong cylinder => recal */
1449 DRS->track = NEED_2_RECAL;
1450 return bad;
1451 case 0x80: /* invalid command given */
1452 DPRINT("Invalid FDC command given!\n");
1453 cont->done(0);
1454 return 2;
1455 case 0xc0:
1456 DPRINT("Abnormal termination caused by polling\n");
1457 cont->error();
1458 return 2;
1459 default: /* (0) Normal command termination */
1460 return 0;
1461 }
1462}
1463
1464/*
1465 * This routine is called when everything should be correctly set up
1466 * for the transfer (i.e. floppy motor is on, the correct floppy is
1467 * selected, and the head is sitting on the right track).
1468 */
1469static void setup_rw_floppy(void)
1470{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001471 int i;
1472 int r;
1473 int flags;
1474 int dflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 unsigned long ready_date;
1476 timeout_fn function;
1477
1478 flags = raw_cmd->flags;
1479 if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1480 flags |= FD_RAW_INTR;
1481
1482 if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1483 ready_date = DRS->spinup_date + DP->spinup;
1484 /* If spinup will take a long time, rerun scandrives
1485 * again just before spinup completion. Beware that
1486 * after scandrives, we must again wait for selection.
1487 */
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08001488 if (time_after(ready_date, jiffies + DP->select_delay)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 ready_date -= DP->select_delay;
Joe Perchesa0a52d62010-03-10 15:20:52 -08001490 function = (timeout_fn)floppy_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 } else
Joe Perchesa0a52d62010-03-10 15:20:52 -08001492 function = (timeout_fn)setup_rw_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493
1494 /* wait until the floppy is spinning fast enough */
1495 if (fd_wait_for_completion(ready_date, function))
1496 return;
1497 }
1498 dflags = DRS->flags;
1499
1500 if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1501 setup_DMA();
1502
1503 if (flags & FD_RAW_INTR)
1504 do_floppy = main_command_interrupt;
1505
1506 r = 0;
1507 for (i = 0; i < raw_cmd->cmd_count; i++)
1508 r |= output_byte(raw_cmd->cmd[i]);
1509
Joe Perchesded28632010-03-10 15:21:09 -08001510 debugt(__func__, "rw_command");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511
1512 if (r) {
1513 cont->error();
1514 reset_fdc();
1515 return;
1516 }
1517
1518 if (!(flags & FD_RAW_INTR)) {
1519 inr = result();
1520 cont->interrupt();
1521 } else if (flags & FD_RAW_NEED_DISK)
1522 fd_watchdog();
1523}
1524
1525static int blind_seek;
1526
1527/*
1528 * This is the routine called after every seek (or recalibrate) interrupt
1529 * from the floppy controller.
1530 */
1531static void seek_interrupt(void)
1532{
Joe Perchesded28632010-03-10 15:21:09 -08001533 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 if (inr != 2 || (ST0 & 0xF8) != 0x20) {
1535 DPRINT("seek failed\n");
1536 DRS->track = NEED_2_RECAL;
1537 cont->error();
1538 cont->redo();
1539 return;
1540 }
1541 if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
Joe Perches87f530d2010-03-10 15:20:54 -08001542 debug_dcl(DP->flags,
1543 "clearing NEWCHANGE flag because of effective seek\n");
1544 debug_dcl(DP->flags, "jiffies=%lu\n", jiffies);
Joe Perchese0298532010-03-10 15:20:55 -08001545 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
1546 /* effective seek */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 DRS->select_date = jiffies;
1548 }
1549 DRS->track = ST1;
1550 floppy_ready();
1551}
1552
1553static void check_wp(void)
1554{
Joe Perchese0298532010-03-10 15:20:55 -08001555 if (test_bit(FD_VERIFY_BIT, &DRS->flags)) {
1556 /* check write protection */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 output_byte(FD_GETSTATUS);
1558 output_byte(UNIT(current_drive));
1559 if (result() != 1) {
1560 FDCS->reset = 1;
1561 return;
1562 }
Joe Perchese0298532010-03-10 15:20:55 -08001563 clear_bit(FD_VERIFY_BIT, &DRS->flags);
1564 clear_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
Joe Perches87f530d2010-03-10 15:20:54 -08001565 debug_dcl(DP->flags,
1566 "checking whether disk is write protected\n");
1567 debug_dcl(DP->flags, "wp=%x\n", ST3 & 0x40);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 if (!(ST3 & 0x40))
Joe Perchese0298532010-03-10 15:20:55 -08001569 set_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 else
Joe Perchese0298532010-03-10 15:20:55 -08001571 clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 }
1573}
1574
1575static void seek_floppy(void)
1576{
1577 int track;
1578
1579 blind_seek = 0;
1580
Joe Perchesded28632010-03-10 15:21:09 -08001581 debug_dcl(DP->flags, "calling disk change from %s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582
Joe Perchese0298532010-03-10 15:20:55 -08001583 if (!test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1585 /* the media changed flag should be cleared after the seek.
1586 * If it isn't, this means that there is really no disk in
1587 * the drive.
1588 */
Joe Perchese0298532010-03-10 15:20:55 -08001589 set_bit(FD_DISK_CHANGED_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 cont->done(0);
1591 cont->redo();
1592 return;
1593 }
1594 if (DRS->track <= NEED_1_RECAL) {
1595 recalibrate_floppy();
1596 return;
Joe Perchese0298532010-03-10 15:20:55 -08001597 } else if (test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1599 (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
1600 /* we seek to clear the media-changed condition. Does anybody
1601 * know a more elegant way, which works on all drives? */
1602 if (raw_cmd->track)
1603 track = raw_cmd->track - 1;
1604 else {
1605 if (DP->flags & FD_SILENT_DCL_CLEAR) {
1606 set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
1607 blind_seek = 1;
1608 raw_cmd->flags |= FD_RAW_NEED_SEEK;
1609 }
1610 track = 1;
1611 }
1612 } else {
1613 check_wp();
1614 if (raw_cmd->track != DRS->track &&
1615 (raw_cmd->flags & FD_RAW_NEED_SEEK))
1616 track = raw_cmd->track;
1617 else {
1618 setup_rw_floppy();
1619 return;
1620 }
1621 }
1622
1623 do_floppy = seek_interrupt;
1624 output_byte(FD_SEEK);
1625 output_byte(UNIT(current_drive));
Joe Perches2300f902010-03-10 15:20:49 -08001626 if (output_byte(track) < 0) {
1627 reset_fdc();
1628 return;
1629 }
Joe Perchesded28632010-03-10 15:21:09 -08001630 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631}
1632
1633static void recal_interrupt(void)
1634{
Joe Perchesded28632010-03-10 15:21:09 -08001635 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 if (inr != 2)
1637 FDCS->reset = 1;
1638 else if (ST0 & ST0_ECE) {
1639 switch (DRS->track) {
1640 case NEED_1_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001641 debugt(__func__, "need 1 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 /* after a second recalibrate, we still haven't
1643 * reached track 0. Probably no drive. Raise an
1644 * error, as failing immediately might upset
1645 * computers possessed by the Devil :-) */
1646 cont->error();
1647 cont->redo();
1648 return;
1649 case NEED_2_RECAL:
Joe Perchesded28632010-03-10 15:21:09 -08001650 debugt(__func__, "need 2 recal");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 /* If we already did a recalibrate,
1652 * and we are not at track 0, this
1653 * means we have moved. (The only way
1654 * not to move at recalibration is to
1655 * be already at track 0.) Clear the
1656 * new change flag */
Joe Perches87f530d2010-03-10 15:20:54 -08001657 debug_dcl(DP->flags,
1658 "clearing NEWCHANGE flag because of second recalibrate\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659
Joe Perchese0298532010-03-10 15:20:55 -08001660 clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 DRS->select_date = jiffies;
1662 /* fall through */
1663 default:
Joe Perchesded28632010-03-10 15:21:09 -08001664 debugt(__func__, "default");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 /* Recalibrate moves the head by at
1666 * most 80 steps. If after one
1667 * recalibrate we don't have reached
1668 * track 0, this might mean that we
1669 * started beyond track 80. Try
1670 * again. */
1671 DRS->track = NEED_1_RECAL;
1672 break;
1673 }
1674 } else
1675 DRS->track = ST1;
1676 floppy_ready();
1677}
1678
1679static void print_result(char *message, int inr)
1680{
1681 int i;
1682
1683 DPRINT("%s ", message);
1684 if (inr >= 0)
1685 for (i = 0; i < inr; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001686 pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1687 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688}
1689
1690/* interrupt handler. Note that this can be called externally on the Sparc */
David Howells7d12e782006-10-05 14:55:46 +01001691irqreturn_t floppy_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 int do_print;
1694 unsigned long f;
Jesper Juhl06f748c2007-10-16 23:30:57 -07001695 void (*handler)(void) = do_floppy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696
1697 lasthandler = handler;
1698 interruptjiffies = jiffies;
1699
1700 f = claim_dma_lock();
1701 fd_disable_dma();
1702 release_dma_lock(f);
1703
1704 floppy_enable_hlt();
1705 do_floppy = NULL;
1706 if (fdc >= N_FDC || FDCS->address == -1) {
1707 /* we don't even know which FDC is the culprit */
Joe Perchesb46df352010-03-10 15:20:46 -08001708 pr_info("DOR0=%x\n", fdc_state[0].dor);
1709 pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
Joe Perches1ebddd82010-03-10 15:21:07 -08001710 pr_info("handler=%pf\n", handler);
Joe Perches275176b2010-03-10 15:21:06 -08001711 is_alive(__func__, "bizarre fdc");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 return IRQ_NONE;
1713 }
1714
1715 FDCS->reset = 0;
1716 /* We have to clear the reset flag here, because apparently on boxes
1717 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1718 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
1719 * emission of the SENSEI's.
1720 * It is OK to emit floppy commands because we are in an interrupt
1721 * handler here, and thus we have to fear no interference of other
1722 * activity.
1723 */
1724
Joe Perches29f1c782010-03-10 15:21:00 -08001725 do_print = !handler && print_unex && initialized;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726
1727 inr = result();
1728 if (do_print)
1729 print_result("unexpected interrupt", inr);
1730 if (inr == 0) {
1731 int max_sensei = 4;
1732 do {
1733 output_byte(FD_SENSEI);
1734 inr = result();
1735 if (do_print)
1736 print_result("sensei", inr);
1737 max_sensei--;
Joe Perchesc5297302010-03-10 15:20:58 -08001738 } while ((ST0 & 0x83) != UNIT(current_drive) &&
1739 inr == 2 && max_sensei);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 }
1741 if (!handler) {
1742 FDCS->reset = 1;
1743 return IRQ_NONE;
1744 }
1745 schedule_bh(handler);
Joe Perches275176b2010-03-10 15:21:06 -08001746 is_alive(__func__, "normal interrupt end");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747
1748 /* FIXME! Was it really for us? */
1749 return IRQ_HANDLED;
1750}
1751
1752static void recalibrate_floppy(void)
1753{
Joe Perchesded28632010-03-10 15:21:09 -08001754 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 do_floppy = recal_interrupt;
1756 output_byte(FD_RECALIBRATE);
Joe Perches15b26302010-03-10 15:21:01 -08001757 if (output_byte(UNIT(current_drive)) < 0)
Joe Perches2300f902010-03-10 15:20:49 -08001758 reset_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759}
1760
1761/*
1762 * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1763 */
1764static void reset_interrupt(void)
1765{
Joe Perchesded28632010-03-10 15:21:09 -08001766 debugt(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 result(); /* get the status ready for set_fdc */
1768 if (FDCS->reset) {
Joe Perches1ebddd82010-03-10 15:21:07 -08001769 pr_info("reset set in interrupt, calling %pf\n", cont->error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 cont->error(); /* a reset just after a reset. BAD! */
1771 }
1772 cont->redo();
1773}
1774
1775/*
1776 * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1777 * or by setting the self clearing bit 7 of STATUS (newer FDCs)
1778 */
1779static void reset_fdc(void)
1780{
1781 unsigned long flags;
1782
1783 do_floppy = reset_interrupt;
1784 FDCS->reset = 0;
1785 reset_fdc_info(0);
1786
1787 /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1788 /* Irrelevant for systems with true DMA (i386). */
1789
1790 flags = claim_dma_lock();
1791 fd_disable_dma();
1792 release_dma_lock(flags);
1793
1794 if (FDCS->version >= FDC_82072A)
1795 fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
1796 else {
1797 fd_outb(FDCS->dor & ~0x04, FD_DOR);
1798 udelay(FD_RESET_DELAY);
1799 fd_outb(FDCS->dor, FD_DOR);
1800 }
1801}
1802
1803static void show_floppy(void)
1804{
1805 int i;
1806
Joe Perchesb46df352010-03-10 15:20:46 -08001807 pr_info("\n");
1808 pr_info("floppy driver state\n");
1809 pr_info("-------------------\n");
Joe Perches1ebddd82010-03-10 15:21:07 -08001810 pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%pf\n",
Joe Perchesb46df352010-03-10 15:20:46 -08001811 jiffies, interruptjiffies, jiffies - interruptjiffies,
1812 lasthandler);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813
Joe Perchesb46df352010-03-10 15:20:46 -08001814 pr_info("timeout_message=%s\n", timeout_message);
1815 pr_info("last output bytes:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 for (i = 0; i < OLOGSIZE; i++)
Joe Perchesb46df352010-03-10 15:20:46 -08001817 pr_info("%2x %2x %lu\n",
1818 output_log[(i + output_log_pos) % OLOGSIZE].data,
1819 output_log[(i + output_log_pos) % OLOGSIZE].status,
1820 output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1821 pr_info("last result at %lu\n", resultjiffies);
1822 pr_info("last redo_fd_request at %lu\n", lastredo);
1823 print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1824 reply_buffer, resultsize, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825
Joe Perchesb46df352010-03-10 15:20:46 -08001826 pr_info("status=%x\n", fd_inb(FD_STATUS));
1827 pr_info("fdc_busy=%lu\n", fdc_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 if (do_floppy)
Joe Perches1ebddd82010-03-10 15:21:07 -08001829 pr_info("do_floppy=%pf\n", do_floppy);
David Howells365970a2006-11-22 14:54:49 +00001830 if (work_pending(&floppy_work))
Joe Perches1ebddd82010-03-10 15:21:07 -08001831 pr_info("floppy_work.func=%pf\n", floppy_work.func);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 if (timer_pending(&fd_timer))
Joe Perches1ebddd82010-03-10 15:21:07 -08001833 pr_info("fd_timer.function=%pf\n", fd_timer.function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 if (timer_pending(&fd_timeout)) {
Joe Perches1ebddd82010-03-10 15:21:07 -08001835 pr_info("timer_function=%pf\n", fd_timeout.function);
Joe Perchesb46df352010-03-10 15:20:46 -08001836 pr_info("expires=%lu\n", fd_timeout.expires - jiffies);
1837 pr_info("now=%lu\n", jiffies);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 }
Joe Perchesb46df352010-03-10 15:20:46 -08001839 pr_info("cont=%p\n", cont);
1840 pr_info("current_req=%p\n", current_req);
1841 pr_info("command_status=%d\n", command_status);
1842 pr_info("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843}
1844
1845static void floppy_shutdown(unsigned long data)
1846{
1847 unsigned long flags;
1848
Joe Perches29f1c782010-03-10 15:21:00 -08001849 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 show_floppy();
1851 cancel_activity();
1852
1853 floppy_enable_hlt();
1854
1855 flags = claim_dma_lock();
1856 fd_disable_dma();
1857 release_dma_lock(flags);
1858
1859 /* avoid dma going to a random drive after shutdown */
1860
Joe Perches29f1c782010-03-10 15:21:00 -08001861 if (initialized)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 DPRINT("floppy timeout called\n");
1863 FDCS->reset = 1;
1864 if (cont) {
1865 cont->done(0);
1866 cont->redo(); /* this will recall reset when needed */
1867 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08001868 pr_info("no cont in shutdown!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 process_fd_request();
1870 }
Joe Perches275176b2010-03-10 15:21:06 -08001871 is_alive(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872}
1873
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874/* start motor, check media-changed condition and write protection */
Jesper Juhl06f748c2007-10-16 23:30:57 -07001875static int start_motor(void (*function)(void))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876{
Jesper Juhl06f748c2007-10-16 23:30:57 -07001877 int mask;
1878 int data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879
1880 mask = 0xfc;
1881 data = UNIT(current_drive);
1882 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1883 if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
1884 set_debugt();
1885 /* no read since this drive is running */
1886 DRS->first_read_date = 0;
1887 /* note motor start time if motor is not yet running */
1888 DRS->spinup_date = jiffies;
1889 data |= (0x10 << UNIT(current_drive));
1890 }
1891 } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
1892 mask &= ~(0x10 << UNIT(current_drive));
1893
1894 /* starts motor and selects floppy */
1895 del_timer(motor_off_timer + current_drive);
1896 set_dor(fdc, mask, data);
1897
1898 /* wait_for_completion also schedules reset if needed. */
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08001899 return fd_wait_for_completion(DRS->select_date + DP->select_delay,
1900 (timeout_fn)function);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901}
1902
1903static void floppy_ready(void)
1904{
Joe Perches045f9832010-03-10 15:20:47 -08001905 if (FDCS->reset) {
1906 reset_fdc();
1907 return;
1908 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 if (start_motor(floppy_ready))
1910 return;
1911 if (fdc_dtr())
1912 return;
1913
Joe Perches87f530d2010-03-10 15:20:54 -08001914 debug_dcl(DP->flags, "calling disk change from floppy_ready\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1916 disk_change(current_drive) && !DP->select_delay)
Joe Perchesbb57f0c2010-03-10 15:20:50 -08001917 twaddle(); /* this clears the dcl on certain
1918 * drive/controller combinations */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919
1920#ifdef fd_chose_dma_mode
1921 if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1922 unsigned long flags = claim_dma_lock();
1923 fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1924 release_dma_lock(flags);
1925 }
1926#endif
1927
1928 if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1929 perpendicular_mode();
1930 fdc_specify(); /* must be done here because of hut, hlt ... */
1931 seek_floppy();
1932 } else {
1933 if ((raw_cmd->flags & FD_RAW_READ) ||
1934 (raw_cmd->flags & FD_RAW_WRITE))
1935 fdc_specify();
1936 setup_rw_floppy();
1937 }
1938}
1939
1940static void floppy_start(void)
1941{
Joe Perches73507e62010-03-10 15:21:03 -08001942 reschedule_timeout(current_reqD, "floppy start");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943
1944 scandrives();
Joe Perches87f530d2010-03-10 15:20:54 -08001945 debug_dcl(DP->flags, "setting NEWCHANGE in floppy_start\n");
Joe Perchese0298532010-03-10 15:20:55 -08001946 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 floppy_ready();
1948}
1949
1950/*
1951 * ========================================================================
1952 * here ends the bottom half. Exported routines are:
1953 * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
1954 * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
1955 * Initialization also uses output_byte, result, set_dor, floppy_interrupt
1956 * and set_dor.
1957 * ========================================================================
1958 */
1959/*
1960 * General purpose continuations.
1961 * ==============================
1962 */
1963
1964static void do_wakeup(void)
1965{
Joe Perches73507e62010-03-10 15:21:03 -08001966 reschedule_timeout(MAXTIMEOUT, "do wakeup");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 cont = NULL;
1968 command_status += 2;
1969 wake_up(&command_done);
1970}
1971
1972static struct cont_t wakeup_cont = {
1973 .interrupt = empty,
1974 .redo = do_wakeup,
1975 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07001976 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977};
1978
1979static struct cont_t intr_cont = {
1980 .interrupt = empty,
1981 .redo = process_fd_request,
1982 .error = empty,
Jesper Juhl06f748c2007-10-16 23:30:57 -07001983 .done = (done_f)empty
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984};
1985
Joe Perches74f63f42010-03-10 15:20:58 -08001986static int wait_til_done(void (*handler)(void), bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987{
1988 int ret;
1989
1990 schedule_bh(handler);
1991
Stephen Hemmingerb862f262010-06-15 13:21:11 +02001992 if (interruptible)
1993 wait_event_interruptible(command_done, command_status >= 2);
1994 else
1995 wait_event(command_done, command_status >= 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996
1997 if (command_status < 2) {
1998 cancel_activity();
1999 cont = &intr_cont;
2000 reset_fdc();
2001 return -EINTR;
2002 }
2003
2004 if (FDCS->reset)
2005 command_status = FD_COMMAND_ERROR;
2006 if (command_status == FD_COMMAND_OKAY)
2007 ret = 0;
2008 else
2009 ret = -EIO;
2010 command_status = FD_COMMAND_NONE;
2011 return ret;
2012}
2013
2014static void generic_done(int result)
2015{
2016 command_status = result;
2017 cont = &wakeup_cont;
2018}
2019
2020static void generic_success(void)
2021{
2022 cont->done(1);
2023}
2024
2025static void generic_failure(void)
2026{
2027 cont->done(0);
2028}
2029
2030static void success_and_wakeup(void)
2031{
2032 generic_success();
2033 cont->redo();
2034}
2035
2036/*
2037 * formatting and rw support.
2038 * ==========================
2039 */
2040
2041static int next_valid_format(void)
2042{
2043 int probed_format;
2044
2045 probed_format = DRS->probed_format;
2046 while (1) {
2047 if (probed_format >= 8 || !DP->autodetect[probed_format]) {
2048 DRS->probed_format = 0;
2049 return 1;
2050 }
2051 if (floppy_type[DP->autodetect[probed_format]].sect) {
2052 DRS->probed_format = probed_format;
2053 return 0;
2054 }
2055 probed_format++;
2056 }
2057}
2058
2059static void bad_flp_intr(void)
2060{
2061 int err_count;
2062
2063 if (probing) {
2064 DRS->probed_format++;
2065 if (!next_valid_format())
2066 return;
2067 }
2068 err_count = ++(*errors);
2069 INFBOUND(DRWE->badness, err_count);
2070 if (err_count > DP->max_errors.abort)
2071 cont->done(0);
2072 if (err_count > DP->max_errors.reset)
2073 FDCS->reset = 1;
2074 else if (err_count > DP->max_errors.recal)
2075 DRS->track = NEED_2_RECAL;
2076}
2077
2078static void set_floppy(int drive)
2079{
2080 int type = ITYPE(UDRS->fd_device);
Jesper Juhl06f748c2007-10-16 23:30:57 -07002081
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 if (type)
2083 _floppy = floppy_type + type;
2084 else
2085 _floppy = current_type[drive];
2086}
2087
2088/*
2089 * formatting support.
2090 * ===================
2091 */
2092static void format_interrupt(void)
2093{
2094 switch (interpret_errors()) {
2095 case 1:
2096 cont->error();
2097 case 2:
2098 break;
2099 case 0:
2100 cont->done(1);
2101 }
2102 cont->redo();
2103}
2104
Joe Perches48c8cee2010-03-10 15:20:45 -08002105#define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106#define CT(x) ((x) | 0xc0)
Joe Perches48c8cee2010-03-10 15:20:45 -08002107
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108static void setup_format_params(int track)
2109{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002110 int n;
2111 int il;
2112 int count;
2113 int head_shift;
2114 int track_shift;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 struct fparm {
2116 unsigned char track, head, sect, size;
2117 } *here = (struct fparm *)floppy_track_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118
2119 raw_cmd = &default_raw_cmd;
2120 raw_cmd->track = track;
2121
Joe Perches48c8cee2010-03-10 15:20:45 -08002122 raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2123 FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 raw_cmd->rate = _floppy->rate & 0x43;
2125 raw_cmd->cmd_count = NR_F;
2126 COMMAND = FM_MODE(_floppy, FD_FORMAT);
2127 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2128 F_SIZECODE = FD_SIZECODE(_floppy);
2129 F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
2130 F_GAP = _floppy->fmt_gap;
2131 F_FILL = FD_FILL_BYTE;
2132
2133 raw_cmd->kernel_data = floppy_track_buffer;
2134 raw_cmd->length = 4 * F_SECT_PER_TRACK;
2135
2136 /* allow for about 30ms for data transport per track */
2137 head_shift = (F_SECT_PER_TRACK + 5) / 6;
2138
2139 /* a ``cylinder'' is two tracks plus a little stepping time */
2140 track_shift = 2 * head_shift + 3;
2141
2142 /* position of logical sector 1 on this track */
2143 n = (track_shift * format_req.track + head_shift * format_req.head)
2144 % F_SECT_PER_TRACK;
2145
2146 /* determine interleave */
2147 il = 1;
2148 if (_floppy->fmt_gap < 0x22)
2149 il++;
2150
2151 /* initialize field */
2152 for (count = 0; count < F_SECT_PER_TRACK; ++count) {
2153 here[count].track = format_req.track;
2154 here[count].head = format_req.head;
2155 here[count].sect = 0;
2156 here[count].size = F_SIZECODE;
2157 }
2158 /* place logical sectors */
2159 for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
2160 here[n].sect = count;
2161 n = (n + il) % F_SECT_PER_TRACK;
2162 if (here[n].sect) { /* sector busy, find next free sector */
2163 ++n;
2164 if (n >= F_SECT_PER_TRACK) {
2165 n -= F_SECT_PER_TRACK;
2166 while (here[n].sect)
2167 ++n;
2168 }
2169 }
2170 }
Keith Wansbrough9e491842008-09-22 14:57:17 -07002171 if (_floppy->stretch & FD_SECTBASEMASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 for (count = 0; count < F_SECT_PER_TRACK; count++)
Keith Wansbrough9e491842008-09-22 14:57:17 -07002173 here[count].sect += FD_SECTBASE(_floppy) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 }
2175}
2176
2177static void redo_format(void)
2178{
2179 buffer_track = -1;
2180 setup_format_params(format_req.track << STRETCH(_floppy));
2181 floppy_start();
Joe Perchesded28632010-03-10 15:21:09 -08002182 debugt(__func__, "queue format request");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183}
2184
2185static struct cont_t format_cont = {
2186 .interrupt = format_interrupt,
2187 .redo = redo_format,
2188 .error = bad_flp_intr,
2189 .done = generic_done
2190};
2191
2192static int do_format(int drive, struct format_descr *tmp_format_req)
2193{
2194 int ret;
2195
Joe Perches74f63f42010-03-10 15:20:58 -08002196 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08002197 return -EINTR;
2198
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 set_floppy(drive);
2200 if (!_floppy ||
2201 _floppy->track > DP->tracks ||
2202 tmp_format_req->track >= _floppy->track ||
2203 tmp_format_req->head >= _floppy->head ||
2204 (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2205 !_floppy->fmt_gap) {
2206 process_fd_request();
2207 return -EINVAL;
2208 }
2209 format_req = *tmp_format_req;
2210 format_errors = 0;
2211 cont = &format_cont;
2212 errors = &format_errors;
Joe Perches74f63f42010-03-10 15:20:58 -08002213 ret = wait_til_done(redo_format, true);
Joe Perches55eee802010-03-10 15:20:57 -08002214 if (ret == -EINTR)
2215 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 process_fd_request();
2217 return ret;
2218}
2219
2220/*
2221 * Buffer read/write and support
2222 * =============================
2223 */
2224
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002225static void floppy_end_request(struct request *req, int error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226{
2227 unsigned int nr_sectors = current_count_sectors;
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002228 unsigned int drive = (unsigned long)req->rq_disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229
2230 /* current_count_sectors can be zero if transfer failed */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002231 if (error)
Tejun Heo83096eb2009-05-07 22:24:39 +09002232 nr_sectors = blk_rq_cur_sectors(req);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002233 if (__blk_end_request(req, error, nr_sectors << 9))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235
2236 /* We're done with the request */
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002237 floppy_off(drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 current_req = NULL;
2239}
2240
2241/* new request_done. Can handle physical sectors which are smaller than a
2242 * logical buffer */
2243static void request_done(int uptodate)
2244{
2245 struct request_queue *q = floppy_queue;
2246 struct request *req = current_req;
2247 unsigned long flags;
2248 int block;
Joe Perches73507e62010-03-10 15:21:03 -08002249 char msg[sizeof("request done ") + sizeof(int) * 3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250
2251 probing = 0;
Joe Perches73507e62010-03-10 15:21:03 -08002252 snprintf(msg, sizeof(msg), "request done %d", uptodate);
2253 reschedule_timeout(MAXTIMEOUT, msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254
2255 if (!req) {
Joe Perchesb46df352010-03-10 15:20:46 -08002256 pr_info("floppy.c: no request in request_done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 return;
2258 }
2259
2260 if (uptodate) {
2261 /* maintain values for invalidation on geometry
2262 * change */
Tejun Heo83096eb2009-05-07 22:24:39 +09002263 block = current_count_sectors + blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 INFBOUND(DRS->maxblock, block);
2265 if (block > _floppy->sect)
2266 DRS->maxtrack = 1;
2267
2268 /* unlock chained buffers */
2269 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002270 floppy_end_request(req, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 spin_unlock_irqrestore(q->queue_lock, flags);
2272 } else {
2273 if (rq_data_dir(req) == WRITE) {
2274 /* record write error information */
2275 DRWE->write_errors++;
2276 if (DRWE->write_errors == 1) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002277 DRWE->first_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 DRWE->first_error_generation = DRS->generation;
2279 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002280 DRWE->last_error_sector = blk_rq_pos(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 DRWE->last_error_generation = DRS->generation;
2282 }
2283 spin_lock_irqsave(q->queue_lock, flags);
Kiyoshi Ueda1c5093b2008-01-28 10:36:21 +01002284 floppy_end_request(req, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 spin_unlock_irqrestore(q->queue_lock, flags);
2286 }
2287}
2288
2289/* Interrupt handler evaluating the result of the r/w operation */
2290static void rw_interrupt(void)
2291{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002292 int eoc;
2293 int ssize;
2294 int heads;
2295 int nr_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296
2297 if (R_HEAD >= 2) {
2298 /* some Toshiba floppy controllers occasionnally seem to
2299 * return bogus interrupts after read/write operations, which
2300 * can be recognized by a bad head number (>= 2) */
2301 return;
2302 }
2303
2304 if (!DRS->first_read_date)
2305 DRS->first_read_date = jiffies;
2306
2307 nr_sectors = 0;
Joe Perches712e1de2010-03-10 15:21:10 -08002308 ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309
2310 if (ST1 & ST1_EOC)
2311 eoc = 1;
2312 else
2313 eoc = 0;
2314
2315 if (COMMAND & 0x80)
2316 heads = 2;
2317 else
2318 heads = 1;
2319
2320 nr_sectors = (((R_TRACK - TRACK) * heads +
2321 R_HEAD - HEAD) * SECT_PER_TRACK +
2322 R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
2323
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 if (nr_sectors / ssize >
Julia Lawall061837b2008-09-22 14:57:16 -07002325 DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 DPRINT("long rw: %x instead of %lx\n",
2327 nr_sectors, current_count_sectors);
Joe Perchesb46df352010-03-10 15:20:46 -08002328 pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
2329 pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
2330 pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
2331 pr_info("heads=%d eoc=%d\n", heads, eoc);
2332 pr_info("spt=%d st=%d ss=%d\n",
2333 SECT_PER_TRACK, fsector_t, ssize);
2334 pr_info("in_sector_offset=%d\n", in_sector_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336
2337 nr_sectors -= in_sector_offset;
2338 INFBOUND(nr_sectors, 0);
2339 SUPBOUND(current_count_sectors, nr_sectors);
2340
2341 switch (interpret_errors()) {
2342 case 2:
2343 cont->redo();
2344 return;
2345 case 1:
2346 if (!current_count_sectors) {
2347 cont->error();
2348 cont->redo();
2349 return;
2350 }
2351 break;
2352 case 0:
2353 if (!current_count_sectors) {
2354 cont->redo();
2355 return;
2356 }
2357 current_type[current_drive] = _floppy;
2358 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2359 break;
2360 }
2361
2362 if (probing) {
2363 if (DP->flags & FTD_MSG)
2364 DPRINT("Auto-detected floppy type %s in fd%d\n",
2365 _floppy->name, current_drive);
2366 current_type[current_drive] = _floppy;
2367 floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2368 probing = 0;
2369 }
2370
2371 if (CT(COMMAND) != FD_READ ||
2372 raw_cmd->kernel_data == current_req->buffer) {
2373 /* transfer directly from buffer */
2374 cont->done(1);
2375 } else if (CT(COMMAND) == FD_READ) {
2376 buffer_track = raw_cmd->track;
2377 buffer_drive = current_drive;
2378 INFBOUND(buffer_max, nr_sectors + fsector_t);
2379 }
2380 cont->redo();
2381}
2382
2383/* Compute maximal contiguous buffer size. */
2384static int buffer_chain_size(void)
2385{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 struct bio_vec *bv;
NeilBrown5705f702007-09-25 12:35:59 +02002387 int size;
2388 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 char *base;
2390
2391 base = bio_data(current_req->bio);
2392 size = 0;
2393
NeilBrown5705f702007-09-25 12:35:59 +02002394 rq_for_each_segment(bv, current_req, iter) {
2395 if (page_address(bv->bv_page) + bv->bv_offset != base + size)
2396 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397
NeilBrown5705f702007-09-25 12:35:59 +02002398 size += bv->bv_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 }
2400
2401 return size >> 9;
2402}
2403
2404/* Compute the maximal transfer size */
2405static int transfer_size(int ssize, int max_sector, int max_size)
2406{
2407 SUPBOUND(max_sector, fsector_t + max_size);
2408
2409 /* alignment */
2410 max_sector -= (max_sector % _floppy->sect) % ssize;
2411
2412 /* transfer size, beginning not aligned */
2413 current_count_sectors = max_sector - fsector_t;
2414
2415 return max_sector;
2416}
2417
2418/*
2419 * Move data from/to the track buffer to/from the buffer cache.
2420 */
2421static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2422{
2423 int remaining; /* number of transferred 512-byte sectors */
2424 struct bio_vec *bv;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002425 char *buffer;
2426 char *dma_buffer;
NeilBrown5705f702007-09-25 12:35:59 +02002427 int size;
2428 struct req_iterator iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429
2430 max_sector = transfer_size(ssize,
2431 min(max_sector, max_sector_2),
Tejun Heo83096eb2009-05-07 22:24:39 +09002432 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433
2434 if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
Tejun Heo83096eb2009-05-07 22:24:39 +09002435 buffer_max > fsector_t + blk_rq_sectors(current_req))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 current_count_sectors = min_t(int, buffer_max - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002437 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438
2439 remaining = current_count_sectors << 9;
Tejun Heo1011c1b2009-05-07 22:24:45 +09002440 if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 DPRINT("in copy buffer\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002442 pr_info("current_count_sectors=%ld\n", current_count_sectors);
2443 pr_info("remaining=%d\n", remaining >> 9);
2444 pr_info("current_req->nr_sectors=%u\n",
2445 blk_rq_sectors(current_req));
2446 pr_info("current_req->current_nr_sectors=%u\n",
2447 blk_rq_cur_sectors(current_req));
2448 pr_info("max_sector=%d\n", max_sector);
2449 pr_info("ssize=%d\n", ssize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451
2452 buffer_max = max(max_sector, buffer_max);
2453
2454 dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2455
Tejun Heo1011c1b2009-05-07 22:24:45 +09002456 size = blk_rq_cur_bytes(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457
NeilBrown5705f702007-09-25 12:35:59 +02002458 rq_for_each_segment(bv, current_req, iter) {
2459 if (!remaining)
2460 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461
NeilBrown5705f702007-09-25 12:35:59 +02002462 size = bv->bv_len;
2463 SUPBOUND(size, remaining);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464
NeilBrown5705f702007-09-25 12:35:59 +02002465 buffer = page_address(bv->bv_page) + bv->bv_offset;
NeilBrown5705f702007-09-25 12:35:59 +02002466 if (dma_buffer + size >
2467 floppy_track_buffer + (max_buffer_sectors << 10) ||
2468 dma_buffer < floppy_track_buffer) {
2469 DPRINT("buffer overrun in copy buffer %d\n",
Joe Perchesb46df352010-03-10 15:20:46 -08002470 (int)((floppy_track_buffer - dma_buffer) >> 9));
2471 pr_info("fsector_t=%d buffer_min=%d\n",
2472 fsector_t, buffer_min);
2473 pr_info("current_count_sectors=%ld\n",
2474 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002476 pr_info("read\n");
NeilBrown5705f702007-09-25 12:35:59 +02002477 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002478 pr_info("write\n");
NeilBrown5705f702007-09-25 12:35:59 +02002479 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 }
NeilBrown5705f702007-09-25 12:35:59 +02002481 if (((unsigned long)buffer) % 512)
2482 DPRINT("%p buffer not aligned\n", buffer);
Joe Perches1a23d132010-03-10 15:21:04 -08002483
NeilBrown5705f702007-09-25 12:35:59 +02002484 if (CT(COMMAND) == FD_READ)
2485 memcpy(buffer, dma_buffer, size);
2486 else
2487 memcpy(dma_buffer, buffer, size);
2488
2489 remaining -= size;
2490 dma_buffer += size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 if (remaining) {
2493 if (remaining > 0)
2494 max_sector -= remaining >> 9;
2495 DPRINT("weirdness: remaining %d\n", remaining >> 9);
2496 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497}
2498
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499/* work around a bug in pseudo DMA
2500 * (on some FDCs) pseudo DMA does not stop when the CPU stops
2501 * sending data. Hence we need a different way to signal the
2502 * transfer length: We use SECT_PER_TRACK. Unfortunately, this
2503 * does not work with MT, hence we can only transfer one head at
2504 * a time
2505 */
2506static void virtualdmabug_workaround(void)
2507{
Jesper Juhl06f748c2007-10-16 23:30:57 -07002508 int hard_sectors;
2509 int end_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510
2511 if (CT(COMMAND) == FD_WRITE) {
2512 COMMAND &= ~0x80; /* switch off multiple track mode */
2513
2514 hard_sectors = raw_cmd->length >> (7 + SIZECODE);
2515 end_sector = SECTOR + hard_sectors - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 if (end_sector > SECT_PER_TRACK) {
Joe Perchesb46df352010-03-10 15:20:46 -08002517 pr_info("too many sectors %d > %d\n",
2518 end_sector, SECT_PER_TRACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 return;
2520 }
Joe Perches48c8cee2010-03-10 15:20:45 -08002521 SECT_PER_TRACK = end_sector;
2522 /* make sure SECT_PER_TRACK
2523 * points to end of transfer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 }
2525}
2526
2527/*
2528 * Formulate a read/write request.
2529 * this routine decides where to load the data (directly to buffer, or to
2530 * tmp floppy area), how much data to load (the size of the buffer, the whole
2531 * track, or a single sector)
2532 * All floppy_track_buffer handling goes in here. If we ever add track buffer
2533 * allocation on the fly, it should be done here. No other part should need
2534 * modification.
2535 */
2536
2537static int make_raw_rw_request(void)
2538{
2539 int aligned_sector_t;
Jesper Juhl06f748c2007-10-16 23:30:57 -07002540 int max_sector;
2541 int max_size;
2542 int tracksize;
2543 int ssize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002545 if (WARN(max_buffer_sectors == 0, "VFS: Block I/O scheduled on unopened device\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547
2548 set_fdc((long)current_req->rq_disk->private_data);
2549
2550 raw_cmd = &default_raw_cmd;
2551 raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK |
2552 FD_RAW_NEED_SEEK;
2553 raw_cmd->cmd_count = NR_RW;
2554 if (rq_data_dir(current_req) == READ) {
2555 raw_cmd->flags |= FD_RAW_READ;
2556 COMMAND = FM_MODE(_floppy, FD_READ);
2557 } else if (rq_data_dir(current_req) == WRITE) {
2558 raw_cmd->flags |= FD_RAW_WRITE;
2559 COMMAND = FM_MODE(_floppy, FD_WRITE);
2560 } else {
Joe Perches275176b2010-03-10 15:21:06 -08002561 DPRINT("%s: unknown command\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 return 0;
2563 }
2564
2565 max_sector = _floppy->sect * _floppy->head;
2566
Tejun Heo83096eb2009-05-07 22:24:39 +09002567 TRACK = (int)blk_rq_pos(current_req) / max_sector;
2568 fsector_t = (int)blk_rq_pos(current_req) % max_sector;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 if (_floppy->track && TRACK >= _floppy->track) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002570 if (blk_rq_cur_sectors(current_req) & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 current_count_sectors = 1;
2572 return 1;
2573 } else
2574 return 0;
2575 }
2576 HEAD = fsector_t / _floppy->sect;
2577
Keith Wansbrough9e491842008-09-22 14:57:17 -07002578 if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
Joe Perchese0298532010-03-10 15:20:55 -08002579 test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags)) &&
2580 fsector_t < _floppy->sect)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 max_sector = _floppy->sect;
2582
2583 /* 2M disks have phantom sectors on the first track */
2584 if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
2585 max_sector = 2 * _floppy->sect / 3;
2586 if (fsector_t >= max_sector) {
2587 current_count_sectors =
2588 min_t(int, _floppy->sect - fsector_t,
Tejun Heo83096eb2009-05-07 22:24:39 +09002589 blk_rq_sectors(current_req));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 return 1;
2591 }
2592 SIZECODE = 2;
2593 } else
2594 SIZECODE = FD_SIZECODE(_floppy);
2595 raw_cmd->rate = _floppy->rate & 0x43;
2596 if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
2597 raw_cmd->rate = 1;
2598
2599 if (SIZECODE)
2600 SIZECODE2 = 0xff;
2601 else
2602 SIZECODE2 = 0x80;
2603 raw_cmd->track = TRACK << STRETCH(_floppy);
2604 DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
2605 GAP = _floppy->gap;
Joe Perches712e1de2010-03-10 15:21:10 -08002606 ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
2608 SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
Keith Wansbrough9e491842008-09-22 14:57:17 -07002609 FD_SECTBASE(_floppy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610
2611 /* tracksize describes the size which can be filled up with sectors
2612 * of size ssize.
2613 */
2614 tracksize = _floppy->sect - _floppy->sect % ssize;
2615 if (tracksize < _floppy->sect) {
2616 SECT_PER_TRACK++;
2617 if (tracksize <= fsector_t % _floppy->sect)
2618 SECTOR--;
2619
2620 /* if we are beyond tracksize, fill up using smaller sectors */
2621 while (tracksize <= fsector_t % _floppy->sect) {
2622 while (tracksize + ssize > _floppy->sect) {
2623 SIZECODE--;
2624 ssize >>= 1;
2625 }
2626 SECTOR++;
2627 SECT_PER_TRACK++;
2628 tracksize += ssize;
2629 }
2630 max_sector = HEAD * _floppy->sect + tracksize;
2631 } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
2632 max_sector = _floppy->sect;
2633 } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
2634 /* for virtual DMA bug workaround */
2635 max_sector = _floppy->sect;
2636 }
2637
2638 in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2639 aligned_sector_t = fsector_t - in_sector_offset;
Tejun Heo83096eb2009-05-07 22:24:39 +09002640 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 if ((raw_cmd->track == buffer_track) &&
2642 (current_drive == buffer_drive) &&
2643 (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2644 /* data already in track buffer */
2645 if (CT(COMMAND) == FD_READ) {
2646 copy_buffer(1, max_sector, buffer_max);
2647 return 1;
2648 }
Tejun Heo83096eb2009-05-07 22:24:39 +09002649 } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 if (CT(COMMAND) == FD_WRITE) {
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002651 unsigned int sectors;
2652
2653 sectors = fsector_t + blk_rq_sectors(current_req);
2654 if (sectors > ssize && sectors < ssize + ssize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 max_size = ssize + ssize;
2656 else
2657 max_size = ssize;
2658 }
2659 raw_cmd->flags &= ~FD_RAW_WRITE;
2660 raw_cmd->flags |= FD_RAW_READ;
2661 COMMAND = FM_MODE(_floppy, FD_READ);
2662 } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) {
2663 unsigned long dma_limit;
2664 int direct, indirect;
2665
2666 indirect =
2667 transfer_size(ssize, max_sector,
2668 max_buffer_sectors * 2) - fsector_t;
2669
2670 /*
2671 * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2672 * on a 64 bit machine!
2673 */
2674 max_size = buffer_chain_size();
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002675 dma_limit = (MAX_DMA_ADDRESS -
2676 ((unsigned long)current_req->buffer)) >> 9;
Joe Perchesa81ee542010-03-10 15:20:46 -08002677 if ((unsigned long)max_size > dma_limit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 max_size = dma_limit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 /* 64 kb boundaries */
2680 if (CROSS_64KB(current_req->buffer, max_size << 9))
2681 max_size = (K_64 -
2682 ((unsigned long)current_req->buffer) %
2683 K_64) >> 9;
2684 direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2685 /*
2686 * We try to read tracks, but if we get too many errors, we
2687 * go back to reading just one sector at a time.
2688 *
2689 * This means we should be able to read a sector even if there
2690 * are other bad sectors on this track.
2691 */
2692 if (!direct ||
2693 (indirect * 2 > direct * 3 &&
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002694 *errors < DP->max_errors.read_track &&
2695 ((!probing ||
2696 (DP->read_track & (1 << DRS->probed_format)))))) {
Tejun Heo83096eb2009-05-07 22:24:39 +09002697 max_size = blk_rq_sectors(current_req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 } else {
2699 raw_cmd->kernel_data = current_req->buffer;
2700 raw_cmd->length = current_count_sectors << 9;
2701 if (raw_cmd->length == 0) {
Joe Perches275176b2010-03-10 15:21:06 -08002702 DPRINT("%s: zero dma transfer attempted\n", __func__);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002703 DPRINT("indirect=%d direct=%d fsector_t=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 indirect, direct, fsector_t);
2705 return 0;
2706 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 virtualdmabug_workaround();
2708 return 2;
2709 }
2710 }
2711
2712 if (CT(COMMAND) == FD_READ)
2713 max_size = max_sector; /* unbounded */
2714
2715 /* claim buffer track if needed */
2716 if (buffer_track != raw_cmd->track || /* bad track */
2717 buffer_drive != current_drive || /* bad drive */
2718 fsector_t > buffer_max ||
2719 fsector_t < buffer_min ||
2720 ((CT(COMMAND) == FD_READ ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002721 (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 max_sector > 2 * max_buffer_sectors + buffer_min &&
Joe Perchesbb57f0c2010-03-10 15:20:50 -08002723 max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
2724 /* not enough space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 buffer_track = -1;
2726 buffer_drive = current_drive;
2727 buffer_max = buffer_min = aligned_sector_t;
2728 }
2729 raw_cmd->kernel_data = floppy_track_buffer +
Joe Perchesbb57f0c2010-03-10 15:20:50 -08002730 ((aligned_sector_t - buffer_min) << 9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731
2732 if (CT(COMMAND) == FD_WRITE) {
2733 /* copy write buffer to track buffer.
2734 * if we get here, we know that the write
2735 * is either aligned or the data already in the buffer
2736 * (buffer will be overwritten) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 if (in_sector_offset && buffer_track == -1)
2738 DPRINT("internal error offset !=0 on write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 buffer_track = raw_cmd->track;
2740 buffer_drive = current_drive;
2741 copy_buffer(ssize, max_sector,
2742 2 * max_buffer_sectors + buffer_min);
2743 } else
2744 transfer_size(ssize, max_sector,
2745 2 * max_buffer_sectors + buffer_min -
2746 aligned_sector_t);
2747
2748 /* round up current_count_sectors to get dma xfer size */
2749 raw_cmd->length = in_sector_offset + current_count_sectors;
2750 raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2751 raw_cmd->length <<= 9;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 if ((raw_cmd->length < current_count_sectors << 9) ||
2753 (raw_cmd->kernel_data != current_req->buffer &&
2754 CT(COMMAND) == FD_WRITE &&
2755 (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2756 aligned_sector_t < buffer_min)) ||
2757 raw_cmd->length % (128 << SIZECODE) ||
2758 raw_cmd->length <= 0 || current_count_sectors <= 0) {
2759 DPRINT("fractionary current count b=%lx s=%lx\n",
2760 raw_cmd->length, current_count_sectors);
2761 if (raw_cmd->kernel_data != current_req->buffer)
Joe Perchesb46df352010-03-10 15:20:46 -08002762 pr_info("addr=%d, length=%ld\n",
2763 (int)((raw_cmd->kernel_data -
2764 floppy_track_buffer) >> 9),
2765 current_count_sectors);
2766 pr_info("st=%d ast=%d mse=%d msi=%d\n",
2767 fsector_t, aligned_sector_t, max_sector, max_size);
2768 pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
2769 pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2770 COMMAND, SECTOR, HEAD, TRACK);
2771 pr_info("buffer drive=%d\n", buffer_drive);
2772 pr_info("buffer track=%d\n", buffer_track);
2773 pr_info("buffer_min=%d\n", buffer_min);
2774 pr_info("buffer_max=%d\n", buffer_max);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 return 0;
2776 }
2777
2778 if (raw_cmd->kernel_data != current_req->buffer) {
2779 if (raw_cmd->kernel_data < floppy_track_buffer ||
2780 current_count_sectors < 0 ||
2781 raw_cmd->length < 0 ||
2782 raw_cmd->kernel_data + raw_cmd->length >
2783 floppy_track_buffer + (max_buffer_sectors << 10)) {
2784 DPRINT("buffer overrun in schedule dma\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002785 pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2786 fsector_t, buffer_min, raw_cmd->length >> 9);
2787 pr_info("current_count_sectors=%ld\n",
2788 current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 if (CT(COMMAND) == FD_READ)
Joe Perchesb46df352010-03-10 15:20:46 -08002790 pr_info("read\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 if (CT(COMMAND) == FD_WRITE)
Joe Perchesb46df352010-03-10 15:20:46 -08002792 pr_info("write\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 return 0;
2794 }
Tejun Heo1011c1b2009-05-07 22:24:45 +09002795 } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
Tejun Heo83096eb2009-05-07 22:24:39 +09002796 current_count_sectors > blk_rq_sectors(current_req)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 DPRINT("buffer overrun in direct transfer\n");
2798 return 0;
2799 } else if (raw_cmd->length < current_count_sectors << 9) {
2800 DPRINT("more sectors than bytes\n");
Joe Perchesb46df352010-03-10 15:20:46 -08002801 pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2802 pr_info("sectors=%ld\n", current_count_sectors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 }
2804 if (raw_cmd->length == 0) {
2805 DPRINT("zero dma transfer attempted from make_raw_request\n");
2806 return 0;
2807 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808
2809 virtualdmabug_workaround();
2810 return 2;
2811}
2812
2813static void redo_fd_request(void)
2814{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 int drive;
2816 int tmp;
2817
2818 lastredo = jiffies;
2819 if (current_drive < N_DRIVE)
2820 floppy_off(current_drive);
2821
Joe Perches0da31322010-03-10 15:21:03 -08002822do_request:
2823 if (!current_req) {
2824 struct request *req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825
Joe Perches0da31322010-03-10 15:21:03 -08002826 spin_lock_irq(floppy_queue->queue_lock);
2827 req = blk_fetch_request(floppy_queue);
2828 spin_unlock_irq(floppy_queue->queue_lock);
2829 if (!req) {
2830 do_floppy = NULL;
2831 unlock_fdc();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 }
Joe Perches0da31322010-03-10 15:21:03 -08002834 current_req = req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 }
Joe Perches0da31322010-03-10 15:21:03 -08002836 drive = (long)current_req->rq_disk->private_data;
2837 set_fdc(drive);
Joe Perches73507e62010-03-10 15:21:03 -08002838 reschedule_timeout(current_reqD, "redo fd request");
Joe Perches0da31322010-03-10 15:21:03 -08002839
2840 set_floppy(drive);
2841 raw_cmd = &default_raw_cmd;
2842 raw_cmd->flags = 0;
2843 if (start_motor(redo_fd_request))
2844 return;
2845
2846 disk_change(current_drive);
2847 if (test_bit(current_drive, &fake_change) ||
2848 test_bit(FD_DISK_CHANGED_BIT, &DRS->flags)) {
2849 DPRINT("disk absent or changed during operation\n");
2850 request_done(0);
2851 goto do_request;
2852 }
2853 if (!_floppy) { /* Autodetection */
2854 if (!probing) {
2855 DRS->probed_format = 0;
2856 if (next_valid_format()) {
2857 DPRINT("no autodetectable formats\n");
2858 _floppy = NULL;
2859 request_done(0);
2860 goto do_request;
2861 }
2862 }
2863 probing = 1;
2864 _floppy = floppy_type + DP->autodetect[DRS->probed_format];
2865 } else
2866 probing = 0;
2867 errors = &(current_req->errors);
2868 tmp = make_raw_rw_request();
2869 if (tmp < 2) {
2870 request_done(tmp);
2871 goto do_request;
2872 }
2873
2874 if (test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags))
2875 twaddle();
2876 schedule_bh(floppy_start);
Joe Perchesded28632010-03-10 15:21:09 -08002877 debugt(__func__, "queue fd request");
Joe Perches0da31322010-03-10 15:21:03 -08002878 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879}
2880
2881static struct cont_t rw_cont = {
2882 .interrupt = rw_interrupt,
2883 .redo = redo_fd_request,
2884 .error = bad_flp_intr,
2885 .done = request_done
2886};
2887
2888static void process_fd_request(void)
2889{
2890 cont = &rw_cont;
2891 schedule_bh(redo_fd_request);
2892}
2893
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08002894static void do_fd_request(struct request_queue *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895{
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002896 if (WARN(max_buffer_sectors == 0,
2897 "VFS: %s called on non-open device\n", __func__))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002900 if (WARN(atomic_read(&usage_count) == 0,
2901 "warning: usage count=0, current_req=%p sect=%ld type=%x flags=%x\n",
2902 current_req, (long)blk_rq_pos(current_req), current_req->cmd_type,
2903 current_req->cmd_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 return;
Stephen Hemminger01b6b672010-06-15 13:21:11 +02002905
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 if (test_bit(0, &fdc_busy)) {
2907 /* fdc busy, this new request will be treated when the
2908 current one is done */
Joe Perches275176b2010-03-10 15:21:06 -08002909 is_alive(__func__, "old request running");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910 return;
2911 }
Joe Perches74f63f42010-03-10 15:20:58 -08002912 lock_fdc(MAXTIMEOUT, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 process_fd_request();
Joe Perches275176b2010-03-10 15:21:06 -08002914 is_alive(__func__, "");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915}
2916
2917static struct cont_t poll_cont = {
2918 .interrupt = success_and_wakeup,
2919 .redo = floppy_ready,
2920 .error = generic_failure,
2921 .done = generic_done
2922};
2923
Joe Perches74f63f42010-03-10 15:20:58 -08002924static int poll_drive(bool interruptible, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 /* no auto-sense, just clear dcl */
2927 raw_cmd = &default_raw_cmd;
2928 raw_cmd->flags = flag;
2929 raw_cmd->track = 0;
2930 raw_cmd->cmd_count = 0;
2931 cont = &poll_cont;
Joe Perches87f530d2010-03-10 15:20:54 -08002932 debug_dcl(DP->flags, "setting NEWCHANGE in poll_drive\n");
Joe Perchese0298532010-03-10 15:20:55 -08002933 set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
Joe Perches55eee802010-03-10 15:20:57 -08002934
2935 return wait_til_done(floppy_ready, interruptible);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936}
2937
2938/*
2939 * User triggered reset
2940 * ====================
2941 */
2942
2943static void reset_intr(void)
2944{
Joe Perchesb46df352010-03-10 15:20:46 -08002945 pr_info("weird, reset interrupt called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946}
2947
2948static struct cont_t reset_cont = {
2949 .interrupt = reset_intr,
2950 .redo = success_and_wakeup,
2951 .error = generic_failure,
2952 .done = generic_done
2953};
2954
Joe Perches74f63f42010-03-10 15:20:58 -08002955static int user_reset_fdc(int drive, int arg, bool interruptible)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956{
2957 int ret;
2958
Joe Perches52a0d612010-03-10 15:20:53 -08002959 if (lock_fdc(drive, interruptible))
2960 return -EINTR;
2961
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 if (arg == FD_RESET_ALWAYS)
2963 FDCS->reset = 1;
2964 if (FDCS->reset) {
2965 cont = &reset_cont;
Joe Perches55eee802010-03-10 15:20:57 -08002966 ret = wait_til_done(reset_fdc, interruptible);
2967 if (ret == -EINTR)
2968 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 }
2970 process_fd_request();
Joe Perches52a0d612010-03-10 15:20:53 -08002971 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972}
2973
2974/*
2975 * Misc Ioctl's and support
2976 * ========================
2977 */
2978static inline int fd_copyout(void __user *param, const void *address,
2979 unsigned long size)
2980{
2981 return copy_to_user(param, address, size) ? -EFAULT : 0;
2982}
2983
Joe Perches48c8cee2010-03-10 15:20:45 -08002984static inline int fd_copyin(void __user *param, void *address,
2985 unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986{
2987 return copy_from_user(address, param, size) ? -EFAULT : 0;
2988}
2989
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02002990static const char *drive_name(int type, int drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991{
2992 struct floppy_struct *floppy;
2993
2994 if (type)
2995 floppy = floppy_type + type;
2996 else {
2997 if (UDP->native_format)
2998 floppy = floppy_type + UDP->native_format;
2999 else
3000 return "(null)";
3001 }
3002 if (floppy->name)
3003 return floppy->name;
3004 else
3005 return "(null)";
3006}
3007
3008/* raw commands */
3009static void raw_cmd_done(int flag)
3010{
3011 int i;
3012
3013 if (!flag) {
3014 raw_cmd->flags |= FD_RAW_FAILURE;
3015 raw_cmd->flags |= FD_RAW_HARDFAILURE;
3016 } else {
3017 raw_cmd->reply_count = inr;
3018 if (raw_cmd->reply_count > MAX_REPLIES)
3019 raw_cmd->reply_count = 0;
3020 for (i = 0; i < raw_cmd->reply_count; i++)
3021 raw_cmd->reply[i] = reply_buffer[i];
3022
3023 if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3024 unsigned long flags;
3025 flags = claim_dma_lock();
3026 raw_cmd->length = fd_get_dma_residue();
3027 release_dma_lock(flags);
3028 }
3029
3030 if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3031 (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3032 raw_cmd->flags |= FD_RAW_FAILURE;
3033
3034 if (disk_change(current_drive))
3035 raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3036 else
3037 raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3038 if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3039 motor_off_callback(current_drive);
3040
3041 if (raw_cmd->next &&
3042 (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3043 !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3044 ((raw_cmd->flags & FD_RAW_FAILURE) ||
3045 !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3046 raw_cmd = raw_cmd->next;
3047 return;
3048 }
3049 }
3050 generic_done(flag);
3051}
3052
3053static struct cont_t raw_cmd_cont = {
3054 .interrupt = success_and_wakeup,
3055 .redo = floppy_start,
3056 .error = generic_failure,
3057 .done = raw_cmd_done
3058};
3059
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003060static int raw_cmd_copyout(int cmd, void __user *param,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 struct floppy_raw_cmd *ptr)
3062{
3063 int ret;
3064
3065 while (ptr) {
Joe Perchesce2f11f2010-03-10 15:21:08 -08003066 ret = copy_to_user(param, ptr, sizeof(*ptr));
Joe Perches86b12b42010-03-10 15:20:56 -08003067 if (ret)
3068 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 param += sizeof(struct floppy_raw_cmd);
3070 if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
Joe Perchesbb57f0c2010-03-10 15:20:50 -08003071 if (ptr->length >= 0 &&
3072 ptr->length <= ptr->buffer_length) {
3073 long length = ptr->buffer_length - ptr->length;
Joe Perches4575b552010-03-10 15:20:55 -08003074 ret = fd_copyout(ptr->data, ptr->kernel_data,
3075 length);
3076 if (ret)
3077 return ret;
Joe Perchesbb57f0c2010-03-10 15:20:50 -08003078 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079 }
3080 ptr = ptr->next;
3081 }
Joe Perches7f252712010-03-10 15:21:08 -08003082
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083 return 0;
3084}
3085
3086static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3087{
Jesper Juhl06f748c2007-10-16 23:30:57 -07003088 struct floppy_raw_cmd *next;
3089 struct floppy_raw_cmd *this;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090
3091 this = *ptr;
3092 *ptr = NULL;
3093 while (this) {
3094 if (this->buffer_length) {
3095 fd_dma_mem_free((unsigned long)this->kernel_data,
3096 this->buffer_length);
3097 this->buffer_length = 0;
3098 }
3099 next = this->next;
3100 kfree(this);
3101 this = next;
3102 }
3103}
3104
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003105static int raw_cmd_copyin(int cmd, void __user *param,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106 struct floppy_raw_cmd **rcmd)
3107{
3108 struct floppy_raw_cmd *ptr;
3109 int ret;
3110 int i;
3111
3112 *rcmd = NULL;
Joe Perches7f252712010-03-10 15:21:08 -08003113
3114loop:
3115 ptr = kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER);
3116 if (!ptr)
3117 return -ENOMEM;
3118 *rcmd = ptr;
3119 ret = copy_from_user(ptr, param, sizeof(*ptr));
3120 if (ret)
3121 return -EFAULT;
3122 ptr->next = NULL;
3123 ptr->buffer_length = 0;
3124 param += sizeof(struct floppy_raw_cmd);
3125 if (ptr->cmd_count > 33)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 /* the command may now also take up the space
3127 * initially intended for the reply & the
3128 * reply count. Needed for long 82078 commands
3129 * such as RESTORE, which takes ... 17 command
3130 * bytes. Murphy's law #137: When you reserve
3131 * 16 bytes for a structure, you'll one day
3132 * discover that you really need 17...
3133 */
Joe Perches7f252712010-03-10 15:21:08 -08003134 return -EINVAL;
3135
3136 for (i = 0; i < 16; i++)
3137 ptr->reply[i] = 0;
3138 ptr->resultcode = 0;
3139 ptr->kernel_data = NULL;
3140
3141 if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3142 if (ptr->length <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 return -EINVAL;
Joe Perches7f252712010-03-10 15:21:08 -08003144 ptr->kernel_data = (char *)fd_dma_mem_alloc(ptr->length);
3145 fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3146 if (!ptr->kernel_data)
3147 return -ENOMEM;
3148 ptr->buffer_length = ptr->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 }
Joe Perches7f252712010-03-10 15:21:08 -08003150 if (ptr->flags & FD_RAW_WRITE) {
3151 ret = fd_copyin(ptr->data, ptr->kernel_data, ptr->length);
3152 if (ret)
3153 return ret;
3154 }
3155
3156 if (ptr->flags & FD_RAW_MORE) {
3157 rcmd = &(ptr->next);
3158 ptr->rate &= 0x43;
3159 goto loop;
3160 }
3161
3162 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163}
3164
3165static int raw_cmd_ioctl(int cmd, void __user *param)
3166{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167 struct floppy_raw_cmd *my_raw_cmd;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003168 int drive;
3169 int ret2;
3170 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171
3172 if (FDCS->rawcmd <= 1)
3173 FDCS->rawcmd = 1;
3174 for (drive = 0; drive < N_DRIVE; drive++) {
3175 if (FDC(drive) != fdc)
3176 continue;
3177 if (drive == current_drive) {
3178 if (UDRS->fd_ref > 1) {
3179 FDCS->rawcmd = 2;
3180 break;
3181 }
3182 } else if (UDRS->fd_ref) {
3183 FDCS->rawcmd = 2;
3184 break;
3185 }
3186 }
3187
3188 if (FDCS->reset)
3189 return -EIO;
3190
3191 ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3192 if (ret) {
3193 raw_cmd_free(&my_raw_cmd);
3194 return ret;
3195 }
3196
3197 raw_cmd = my_raw_cmd;
3198 cont = &raw_cmd_cont;
Joe Perches74f63f42010-03-10 15:20:58 -08003199 ret = wait_til_done(floppy_start, true);
Joe Perches87f530d2010-03-10 15:20:54 -08003200 debug_dcl(DP->flags, "calling disk change from raw_cmd ioctl\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201
3202 if (ret != -EINTR && FDCS->reset)
3203 ret = -EIO;
3204
3205 DRS->track = NO_TRACK;
3206
3207 ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3208 if (!ret)
3209 ret = ret2;
3210 raw_cmd_free(&my_raw_cmd);
3211 return ret;
3212}
3213
3214static int invalidate_drive(struct block_device *bdev)
3215{
3216 /* invalidate the buffer track to force a reread */
3217 set_bit((long)bdev->bd_disk->private_data, &fake_change);
3218 process_fd_request();
3219 check_disk_change(bdev);
3220 return 0;
3221}
3222
Stephen Hemmingerbe7a12b2010-06-15 13:21:11 +02003223static int set_geometry(unsigned int cmd, struct floppy_struct *g,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224 int drive, int type, struct block_device *bdev)
3225{
3226 int cnt;
3227
3228 /* sanity checking for parameters. */
3229 if (g->sect <= 0 ||
3230 g->head <= 0 ||
3231 g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
3232 /* check if reserved bits are set */
Keith Wansbrough9e491842008-09-22 14:57:17 -07003233 (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 return -EINVAL;
3235 if (type) {
3236 if (!capable(CAP_SYS_ADMIN))
3237 return -EPERM;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003238 mutex_lock(&open_lock);
Joe Perches74f63f42010-03-10 15:20:58 -08003239 if (lock_fdc(drive, true)) {
Jiri Slaby8516a502009-06-30 11:41:44 -07003240 mutex_unlock(&open_lock);
3241 return -EINTR;
3242 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243 floppy_type[type] = *g;
3244 floppy_type[type].name = "user format";
3245 for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3246 floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3247 floppy_type[type].size + 1;
3248 process_fd_request();
3249 for (cnt = 0; cnt < N_DRIVE; cnt++) {
3250 struct block_device *bdev = opened_bdev[cnt];
3251 if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3252 continue;
Christoph Hellwig2ef41632005-05-05 16:15:59 -07003253 __invalidate_device(bdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003255 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 } else {
3257 int oldStretch;
Joe Perches52a0d612010-03-10 15:20:53 -08003258
Joe Perches74f63f42010-03-10 15:20:58 -08003259 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003260 return -EINTR;
Joe Perches4575b552010-03-10 15:20:55 -08003261 if (cmd != FDDEFPRM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 /* notice a disk change immediately, else
3263 * we lose our settings immediately*/
Joe Perches74f63f42010-03-10 15:20:58 -08003264 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003265 return -EINTR;
3266 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267 oldStretch = g->stretch;
3268 user_params[drive] = *g;
3269 if (buffer_drive == drive)
3270 SUPBOUND(buffer_max, user_params[drive].sect);
3271 current_type[drive] = &user_params[drive];
3272 floppy_sizes[drive] = user_params[drive].size;
3273 if (cmd == FDDEFPRM)
3274 DRS->keep_data = -1;
3275 else
3276 DRS->keep_data = 1;
3277 /* invalidation. Invalidate only when needed, i.e.
3278 * when there are already sectors in the buffer cache
3279 * whose number will change. This is useful, because
3280 * mtools often changes the geometry of the disk after
3281 * looking at the boot block */
3282 if (DRS->maxblock > user_params[drive].sect ||
3283 DRS->maxtrack ||
3284 ((user_params[drive].sect ^ oldStretch) &
Keith Wansbrough9e491842008-09-22 14:57:17 -07003285 (FD_SWAPSIDES | FD_SECTBASEMASK)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286 invalidate_drive(bdev);
3287 else
3288 process_fd_request();
3289 }
3290 return 0;
3291}
3292
3293/* handle obsolete ioctl's */
Stephen Hemminger21af5442010-06-15 13:21:11 +02003294static unsigned int ioctl_table[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 FDCLRPRM,
3296 FDSETPRM,
3297 FDDEFPRM,
3298 FDGETPRM,
3299 FDMSGON,
3300 FDMSGOFF,
3301 FDFMTBEG,
3302 FDFMTTRK,
3303 FDFMTEND,
3304 FDSETEMSGTRESH,
3305 FDFLUSH,
3306 FDSETMAXERRS,
3307 FDGETMAXERRS,
3308 FDGETDRVTYP,
3309 FDSETDRVPRM,
3310 FDGETDRVPRM,
3311 FDGETDRVSTAT,
3312 FDPOLLDRVSTAT,
3313 FDRESET,
3314 FDGETFDCSTAT,
3315 FDWERRORCLR,
3316 FDWERRORGET,
3317 FDRAWCMD,
3318 FDEJECT,
3319 FDTWADDLE
3320};
3321
Stephen Hemminger21af5442010-06-15 13:21:11 +02003322static int normalize_ioctl(unsigned int *cmd, int *size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323{
3324 int i;
3325
3326 for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3327 if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3328 *size = _IOC_SIZE(*cmd);
3329 *cmd = ioctl_table[i];
3330 if (*size > _IOC_SIZE(*cmd)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003331 pr_info("ioctl not yet supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 return -EFAULT;
3333 }
3334 return 0;
3335 }
3336 }
3337 return -EINVAL;
3338}
3339
3340static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3341{
3342 if (type)
3343 *g = &floppy_type[type];
3344 else {
Joe Perches74f63f42010-03-10 15:20:58 -08003345 if (lock_fdc(drive, false))
Joe Perches52a0d612010-03-10 15:20:53 -08003346 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003347 if (poll_drive(false, 0) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003348 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349 process_fd_request();
3350 *g = current_type[drive];
3351 }
3352 if (!*g)
3353 return -ENODEV;
3354 return 0;
3355}
3356
Christoph Hellwiga885c8c2006-01-08 01:02:50 -08003357static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3358{
3359 int drive = (long)bdev->bd_disk->private_data;
3360 int type = ITYPE(drive_state[drive].fd_device);
3361 struct floppy_struct *g;
3362 int ret;
3363
3364 ret = get_floppy_geometry(drive, type, &g);
3365 if (ret)
3366 return ret;
3367
3368 geo->heads = g->head;
3369 geo->sectors = g->sect;
3370 geo->cylinders = g->track;
3371 return 0;
3372}
3373
Al Viroa4af9b42008-03-02 09:27:55 -05003374static int fd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 unsigned long param)
3376{
Al Viroa4af9b42008-03-02 09:27:55 -05003377 int drive = (long)bdev->bd_disk->private_data;
Jesper Juhl06f748c2007-10-16 23:30:57 -07003378 int type = ITYPE(UDRS->fd_device);
3379 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 int ret;
3381 int size;
3382 union inparam {
3383 struct floppy_struct g; /* geometry */
3384 struct format_descr f;
3385 struct floppy_max_errors max_errors;
3386 struct floppy_drive_params dp;
3387 } inparam; /* parameters coming from user space */
Joe Perches724ee622010-03-10 15:21:11 -08003388 const void *outparam; /* parameters passed back to user space */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389
3390 /* convert compatibility eject ioctls into floppy eject ioctl.
3391 * We do this in order to provide a means to eject floppy disks before
3392 * installing the new fdutils package */
3393 if (cmd == CDROMEJECT || /* CD-ROM eject */
Joe Perchesa81ee542010-03-10 15:20:46 -08003394 cmd == 0x6470) { /* SunOS floppy eject */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395 DPRINT("obsolete eject ioctl\n");
3396 DPRINT("please use floppycontrol --eject\n");
3397 cmd = FDEJECT;
3398 }
3399
Joe Perchesa81ee542010-03-10 15:20:46 -08003400 if (!((cmd & 0xff00) == 0x0200))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 return -EINVAL;
3402
Joe Perchesa81ee542010-03-10 15:20:46 -08003403 /* convert the old style command into a new style command */
Joe Perches4575b552010-03-10 15:20:55 -08003404 ret = normalize_ioctl(&cmd, &size);
3405 if (ret)
3406 return ret;
Joe Perchesa81ee542010-03-10 15:20:46 -08003407
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408 /* permission checks */
Joe Perches0aad92c2010-03-10 15:21:10 -08003409 if (((cmd & 0x40) && !(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL))) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410 ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3411 return -EPERM;
3412
Arjan van de Ven2886a8b2009-12-14 18:00:11 -08003413 if (WARN_ON(size < 0 || size > sizeof(inparam)))
3414 return -EINVAL;
3415
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 /* copyin */
Joe Perchesb87c9e02010-03-10 15:20:50 -08003417 memset(&inparam, 0, sizeof(inparam));
Joe Perches4575b552010-03-10 15:20:55 -08003418 if (_IOC_DIR(cmd) & _IOC_WRITE) {
3419 ret = fd_copyin((void __user *)param, &inparam, size);
3420 if (ret)
3421 return ret;
3422 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423
Joe Perchesda273652010-03-10 15:20:52 -08003424 switch (cmd) {
3425 case FDEJECT:
3426 if (UDRS->fd_ref != 1)
3427 /* somebody else has this drive open */
3428 return -EBUSY;
Joe Perches74f63f42010-03-10 15:20:58 -08003429 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003430 return -EINTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431
Joe Perchesda273652010-03-10 15:20:52 -08003432 /* do the actual eject. Fails on
3433 * non-Sparc architectures */
3434 ret = fd_eject(UNIT(drive));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435
Joe Perchese0298532010-03-10 15:20:55 -08003436 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3437 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Joe Perchesda273652010-03-10 15:20:52 -08003438 process_fd_request();
3439 return ret;
3440 case FDCLRPRM:
Joe Perches74f63f42010-03-10 15:20:58 -08003441 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003442 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003443 current_type[drive] = NULL;
3444 floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3445 UDRS->keep_data = 0;
3446 return invalidate_drive(bdev);
3447 case FDSETPRM:
3448 case FDDEFPRM:
3449 return set_geometry(cmd, &inparam.g, drive, type, bdev);
3450 case FDGETPRM:
Joe Perches4575b552010-03-10 15:20:55 -08003451 ret = get_floppy_geometry(drive, type,
Joe Perches724ee622010-03-10 15:21:11 -08003452 (struct floppy_struct **)&outparam);
Joe Perches4575b552010-03-10 15:20:55 -08003453 if (ret)
3454 return ret;
Joe Perchesda273652010-03-10 15:20:52 -08003455 break;
3456 case FDMSGON:
3457 UDP->flags |= FTD_MSG;
3458 return 0;
3459 case FDMSGOFF:
3460 UDP->flags &= ~FTD_MSG;
3461 return 0;
3462 case FDFMTBEG:
Joe Perches74f63f42010-03-10 15:20:58 -08003463 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003464 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003465 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003466 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003467 ret = UDRS->flags;
3468 process_fd_request();
3469 if (ret & FD_VERIFY)
3470 return -ENODEV;
3471 if (!(ret & FD_DISK_WRITABLE))
3472 return -EROFS;
3473 return 0;
3474 case FDFMTTRK:
3475 if (UDRS->fd_ref != 1)
3476 return -EBUSY;
3477 return do_format(drive, &inparam.f);
3478 case FDFMTEND:
3479 case FDFLUSH:
Joe Perches74f63f42010-03-10 15:20:58 -08003480 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003481 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003482 return invalidate_drive(bdev);
3483 case FDSETEMSGTRESH:
3484 UDP->max_errors.reporting = (unsigned short)(param & 0x0f);
3485 return 0;
3486 case FDGETMAXERRS:
Joe Perches724ee622010-03-10 15:21:11 -08003487 outparam = &UDP->max_errors;
Joe Perchesda273652010-03-10 15:20:52 -08003488 break;
3489 case FDSETMAXERRS:
3490 UDP->max_errors = inparam.max_errors;
3491 break;
3492 case FDGETDRVTYP:
3493 outparam = drive_name(type, drive);
Joe Perches724ee622010-03-10 15:21:11 -08003494 SUPBOUND(size, strlen((const char *)outparam) + 1);
Joe Perchesda273652010-03-10 15:20:52 -08003495 break;
3496 case FDSETDRVPRM:
3497 *UDP = inparam.dp;
3498 break;
3499 case FDGETDRVPRM:
Joe Perches724ee622010-03-10 15:21:11 -08003500 outparam = UDP;
Joe Perchesda273652010-03-10 15:20:52 -08003501 break;
3502 case FDPOLLDRVSTAT:
Joe Perches74f63f42010-03-10 15:20:58 -08003503 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003504 return -EINTR;
Joe Perches74f63f42010-03-10 15:20:58 -08003505 if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
Joe Perches4575b552010-03-10 15:20:55 -08003506 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003507 process_fd_request();
3508 /* fall through */
3509 case FDGETDRVSTAT:
Joe Perches724ee622010-03-10 15:21:11 -08003510 outparam = UDRS;
Joe Perchesda273652010-03-10 15:20:52 -08003511 break;
3512 case FDRESET:
Joe Perches74f63f42010-03-10 15:20:58 -08003513 return user_reset_fdc(drive, (int)param, true);
Joe Perchesda273652010-03-10 15:20:52 -08003514 case FDGETFDCSTAT:
Joe Perches724ee622010-03-10 15:21:11 -08003515 outparam = UFDCS;
Joe Perchesda273652010-03-10 15:20:52 -08003516 break;
3517 case FDWERRORCLR:
3518 memset(UDRWE, 0, sizeof(*UDRWE));
3519 return 0;
3520 case FDWERRORGET:
Joe Perches724ee622010-03-10 15:21:11 -08003521 outparam = UDRWE;
Joe Perchesda273652010-03-10 15:20:52 -08003522 break;
3523 case FDRAWCMD:
3524 if (type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 return -EINVAL;
Joe Perches74f63f42010-03-10 15:20:58 -08003526 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003527 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003528 set_floppy(drive);
Joe Perches4575b552010-03-10 15:20:55 -08003529 i = raw_cmd_ioctl(cmd, (void __user *)param);
3530 if (i == -EINTR)
3531 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003532 process_fd_request();
3533 return i;
3534 case FDTWADDLE:
Joe Perches74f63f42010-03-10 15:20:58 -08003535 if (lock_fdc(drive, true))
Joe Perches52a0d612010-03-10 15:20:53 -08003536 return -EINTR;
Joe Perchesda273652010-03-10 15:20:52 -08003537 twaddle();
3538 process_fd_request();
3539 return 0;
3540 default:
3541 return -EINVAL;
3542 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543
3544 if (_IOC_DIR(cmd) & _IOC_READ)
3545 return fd_copyout((void __user *)param, outparam, size);
Joe Perchesda273652010-03-10 15:20:52 -08003546
3547 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548}
3549
3550static void __init config_types(void)
3551{
Joe Perchesb46df352010-03-10 15:20:46 -08003552 bool has_drive = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 int drive;
3554
3555 /* read drive info out of physical CMOS */
3556 drive = 0;
3557 if (!UDP->cmos)
3558 UDP->cmos = FLOPPY0_TYPE;
3559 drive = 1;
3560 if (!UDP->cmos && FLOPPY1_TYPE)
3561 UDP->cmos = FLOPPY1_TYPE;
3562
Jesper Juhl06f748c2007-10-16 23:30:57 -07003563 /* FIXME: additional physical CMOS drive detection should go here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564
3565 for (drive = 0; drive < N_DRIVE; drive++) {
3566 unsigned int type = UDP->cmos;
3567 struct floppy_drive_params *params;
3568 const char *name = NULL;
3569 static char temparea[32];
3570
Tobias Klauser945f3902006-01-08 01:05:11 -08003571 if (type < ARRAY_SIZE(default_drive_params)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572 params = &default_drive_params[type].params;
3573 if (type) {
3574 name = default_drive_params[type].name;
3575 allowed_drive_mask |= 1 << drive;
3576 } else
3577 allowed_drive_mask &= ~(1 << drive);
3578 } else {
3579 params = &default_drive_params[0].params;
3580 sprintf(temparea, "unknown type %d (usb?)", type);
3581 name = temparea;
3582 }
3583 if (name) {
Joe Perchesb46df352010-03-10 15:20:46 -08003584 const char *prepend;
3585 if (!has_drive) {
3586 prepend = "";
3587 has_drive = true;
3588 pr_info("Floppy drive(s):");
3589 } else {
3590 prepend = ",";
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 }
Joe Perchesb46df352010-03-10 15:20:46 -08003592
3593 pr_cont("%s fd%d is %s", prepend, drive, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 }
3595 *UDP = *params;
3596 }
Joe Perchesb46df352010-03-10 15:20:46 -08003597
3598 if (has_drive)
3599 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600}
3601
Al Viroa4af9b42008-03-02 09:27:55 -05003602static int floppy_release(struct gendisk *disk, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603{
Al Viroa4af9b42008-03-02 09:27:55 -05003604 int drive = (long)disk->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003606 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 if (UDRS->fd_ref < 0)
3608 UDRS->fd_ref = 0;
3609 else if (!UDRS->fd_ref--) {
3610 DPRINT("floppy_release with fd_ref == 0");
3611 UDRS->fd_ref = 0;
3612 }
3613 if (!UDRS->fd_ref)
3614 opened_bdev[drive] = NULL;
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003615 mutex_unlock(&open_lock);
Ingo Molnar3e541a42006-07-03 00:24:23 -07003616
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 return 0;
3618}
3619
3620/*
3621 * floppy_open check for aliasing (/dev/fd0 can be the same as
3622 * /dev/PS0 etc), and disallows simultaneous access to the same
3623 * drive with different device numbers.
3624 */
Al Viroa4af9b42008-03-02 09:27:55 -05003625static int floppy_open(struct block_device *bdev, fmode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626{
Al Viroa4af9b42008-03-02 09:27:55 -05003627 int drive = (long)bdev->bd_disk->private_data;
3628 int old_dev, new_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629 int try;
3630 int res = -EBUSY;
3631 char *tmp;
3632
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003633 mutex_lock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 old_dev = UDRS->fd_device;
Al Viroa4af9b42008-03-02 09:27:55 -05003635 if (opened_bdev[drive] && opened_bdev[drive] != bdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 goto out2;
3637
3638 if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
Joe Perchese0298532010-03-10 15:20:55 -08003639 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
3640 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 }
3642
Al Viroa4af9b42008-03-02 09:27:55 -05003643 if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (mode & FMODE_EXCL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644 goto out2;
3645
Al Viroa4af9b42008-03-02 09:27:55 -05003646 if (mode & FMODE_EXCL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647 UDRS->fd_ref = -1;
3648 else
3649 UDRS->fd_ref++;
3650
Al Viroa4af9b42008-03-02 09:27:55 -05003651 opened_bdev[drive] = bdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652
3653 res = -ENXIO;
3654
3655 if (!floppy_track_buffer) {
3656 /* if opening an ED drive, reserve a big buffer,
3657 * else reserve a small one */
3658 if ((UDP->cmos == 6) || (UDP->cmos == 5))
3659 try = 64; /* Only 48 actually useful */
3660 else
3661 try = 32; /* Only 24 actually useful */
3662
3663 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3664 if (!tmp && !floppy_track_buffer) {
3665 try >>= 1; /* buffer only one side */
3666 INFBOUND(try, 16);
3667 tmp = (char *)fd_dma_mem_alloc(1024 * try);
3668 }
Joe Perchesa81ee542010-03-10 15:20:46 -08003669 if (!tmp && !floppy_track_buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 fallback_on_nodma_alloc(&tmp, 2048 * try);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671 if (!tmp && !floppy_track_buffer) {
3672 DPRINT("Unable to allocate DMA memory\n");
3673 goto out;
3674 }
3675 if (floppy_track_buffer) {
3676 if (tmp)
3677 fd_dma_mem_free((unsigned long)tmp, try * 1024);
3678 } else {
3679 buffer_min = buffer_max = -1;
3680 floppy_track_buffer = tmp;
3681 max_buffer_sectors = try;
3682 }
3683 }
3684
Al Viroa4af9b42008-03-02 09:27:55 -05003685 new_dev = MINOR(bdev->bd_dev);
3686 UDRS->fd_device = new_dev;
3687 set_capacity(disks[drive], floppy_sizes[new_dev]);
3688 if (old_dev != -1 && old_dev != new_dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689 if (buffer_drive == drive)
3690 buffer_track = -1;
3691 }
3692
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 if (UFDCS->rawcmd == 1)
3694 UFDCS->rawcmd = 2;
3695
Al Viroa4af9b42008-03-02 09:27:55 -05003696 if (!(mode & FMODE_NDELAY)) {
3697 if (mode & (FMODE_READ|FMODE_WRITE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 UDRS->last_checked = 0;
Al Viroa4af9b42008-03-02 09:27:55 -05003699 check_disk_change(bdev);
Joe Perchese0298532010-03-10 15:20:55 -08003700 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 goto out;
3702 }
3703 res = -EROFS;
Joe Perchese0298532010-03-10 15:20:55 -08003704 if ((mode & FMODE_WRITE) &&
3705 !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 goto out;
3707 }
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003708 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 return 0;
3710out:
3711 if (UDRS->fd_ref < 0)
3712 UDRS->fd_ref = 0;
3713 else
3714 UDRS->fd_ref--;
3715 if (!UDRS->fd_ref)
3716 opened_bdev[drive] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717out2:
Jes Sorensenb1c82b52006-03-23 03:00:26 -08003718 mutex_unlock(&open_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719 return res;
3720}
3721
3722/*
3723 * Check if the disk has been changed or if a change has been faked.
3724 */
3725static int check_floppy_change(struct gendisk *disk)
3726{
3727 int drive = (long)disk->private_data;
3728
Joe Perchese0298532010-03-10 15:20:55 -08003729 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3730 test_bit(FD_VERIFY_BIT, &UDRS->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731 return 1;
3732
Marcelo Feitoza Parisi50297cb2006-03-28 01:56:44 -08003733 if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
Joe Perches74f63f42010-03-10 15:20:58 -08003734 lock_fdc(drive, false);
3735 poll_drive(false, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 process_fd_request();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003737 }
3738
Joe Perchese0298532010-03-10 15:20:55 -08003739 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3740 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741 test_bit(drive, &fake_change) ||
3742 (!ITYPE(UDRS->fd_device) && !current_type[drive]))
3743 return 1;
3744 return 0;
3745}
3746
3747/*
3748 * This implements "read block 0" for floppy_revalidate().
3749 * Needed for format autodetection, checking whether there is
3750 * a disk in the drive, and whether that disk is writable.
3751 */
3752
Joe Perchesbb57f0c2010-03-10 15:20:50 -08003753static void floppy_rb0_complete(struct bio *bio, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755 complete((struct completion *)bio->bi_private);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756}
3757
3758static int __floppy_read_block_0(struct block_device *bdev)
3759{
3760 struct bio bio;
3761 struct bio_vec bio_vec;
3762 struct completion complete;
3763 struct page *page;
3764 size_t size;
3765
3766 page = alloc_page(GFP_NOIO);
3767 if (!page) {
3768 process_fd_request();
3769 return -ENOMEM;
3770 }
3771
3772 size = bdev->bd_block_size;
3773 if (!size)
3774 size = 1024;
3775
3776 bio_init(&bio);
3777 bio.bi_io_vec = &bio_vec;
3778 bio_vec.bv_page = page;
3779 bio_vec.bv_len = size;
3780 bio_vec.bv_offset = 0;
3781 bio.bi_vcnt = 1;
3782 bio.bi_idx = 0;
3783 bio.bi_size = size;
3784 bio.bi_bdev = bdev;
3785 bio.bi_sector = 0;
Stephen Hemminger41a55b42010-06-15 13:21:11 +02003786 bio.bi_flags = BIO_QUIET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 init_completion(&complete);
3788 bio.bi_private = &complete;
3789 bio.bi_end_io = floppy_rb0_complete;
3790
3791 submit_bio(READ, &bio);
3792 generic_unplug_device(bdev_get_queue(bdev));
3793 process_fd_request();
3794 wait_for_completion(&complete);
3795
3796 __free_page(page);
3797
3798 return 0;
3799}
3800
3801/* revalidate the floppy disk, i.e. trigger format autodetection by reading
3802 * the bootblock (block 0). "Autodetection" is also needed to check whether
3803 * there is a disk in the drive at all... Thus we also do it for fixed
3804 * geometry formats */
3805static int floppy_revalidate(struct gendisk *disk)
3806{
3807 int drive = (long)disk->private_data;
3808#define NO_GEOM (!current_type[drive] && !ITYPE(UDRS->fd_device))
3809 int cf;
3810 int res = 0;
3811
Joe Perchese0298532010-03-10 15:20:55 -08003812 if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3813 test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
3814 test_bit(drive, &fake_change) || NO_GEOM) {
Stephen Hemminger01b6b672010-06-15 13:21:11 +02003815 if (WARN(atomic_read(&usage_count) == 0,
3816 "VFS: revalidate called on non-open device.\n"))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 return -EFAULT;
Stephen Hemminger01b6b672010-06-15 13:21:11 +02003818
Joe Perches74f63f42010-03-10 15:20:58 -08003819 lock_fdc(drive, false);
Joe Perchese0298532010-03-10 15:20:55 -08003820 cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
3821 test_bit(FD_VERIFY_BIT, &UDRS->flags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822 if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)) {
3823 process_fd_request(); /*already done by another thread */
3824 return 0;
3825 }
3826 UDRS->maxblock = 0;
3827 UDRS->maxtrack = 0;
3828 if (buffer_drive == drive)
3829 buffer_track = -1;
3830 clear_bit(drive, &fake_change);
Joe Perchese0298532010-03-10 15:20:55 -08003831 clear_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832 if (cf)
3833 UDRS->generation++;
3834 if (NO_GEOM) {
3835 /* auto-sensing */
3836 res = __floppy_read_block_0(opened_bdev[drive]);
3837 } else {
3838 if (cf)
Joe Perches74f63f42010-03-10 15:20:58 -08003839 poll_drive(false, FD_RAW_NEED_DISK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840 process_fd_request();
3841 }
3842 }
3843 set_capacity(disk, floppy_sizes[UDRS->fd_device]);
3844 return res;
3845}
3846
Alexey Dobriyan83d5cde2009-09-21 17:01:13 -07003847static const struct block_device_operations floppy_fops = {
Jesper Juhl06f748c2007-10-16 23:30:57 -07003848 .owner = THIS_MODULE,
Al Viroa4af9b42008-03-02 09:27:55 -05003849 .open = floppy_open,
3850 .release = floppy_release,
3851 .locked_ioctl = fd_ioctl,
Jesper Juhl06f748c2007-10-16 23:30:57 -07003852 .getgeo = fd_getgeo,
3853 .media_changed = check_floppy_change,
3854 .revalidate_disk = floppy_revalidate,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857/*
3858 * Floppy Driver initialization
3859 * =============================
3860 */
3861
3862/* Determine the floppy disk controller type */
3863/* This routine was written by David C. Niemi */
3864static char __init get_fdc_version(void)
3865{
3866 int r;
3867
3868 output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
3869 if (FDCS->reset)
3870 return FDC_NONE;
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003871 r = result();
3872 if (r <= 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 return FDC_NONE; /* No FDC present ??? */
3874 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003875 pr_info("FDC %d is an 8272A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876 return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
3877 }
3878 if (r != 10) {
Joe Perchesb46df352010-03-10 15:20:46 -08003879 pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
3880 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 return FDC_UNKNOWN;
3882 }
3883
3884 if (!fdc_configure()) {
Joe Perchesb46df352010-03-10 15:20:46 -08003885 pr_info("FDC %d is an 82072\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 return FDC_82072; /* 82072 doesn't know CONFIGURE */
3887 }
3888
3889 output_byte(FD_PERPENDICULAR);
3890 if (need_more_output() == MORE_OUTPUT) {
3891 output_byte(0);
3892 } else {
Joe Perchesb46df352010-03-10 15:20:46 -08003893 pr_info("FDC %d is an 82072A\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894 return FDC_82072A; /* 82072A as found on Sparcs. */
3895 }
3896
3897 output_byte(FD_UNLOCK);
3898 r = result();
3899 if ((r == 1) && (reply_buffer[0] == 0x80)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003900 pr_info("FDC %d is a pre-1991 82077\n", fdc);
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08003901 return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 * LOCK/UNLOCK */
3903 }
3904 if ((r != 1) || (reply_buffer[0] != 0x00)) {
Joe Perchesb46df352010-03-10 15:20:46 -08003905 pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
3906 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 return FDC_UNKNOWN;
3908 }
3909 output_byte(FD_PARTID);
3910 r = result();
3911 if (r != 1) {
Joe Perchesb46df352010-03-10 15:20:46 -08003912 pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
3913 fdc, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914 return FDC_UNKNOWN;
3915 }
3916 if (reply_buffer[0] == 0x80) {
Joe Perchesb46df352010-03-10 15:20:46 -08003917 pr_info("FDC %d is a post-1991 82077\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918 return FDC_82077; /* Revised 82077AA passes all the tests */
3919 }
3920 switch (reply_buffer[0] >> 5) {
3921 case 0x0:
3922 /* Either a 82078-1 or a 82078SL running at 5Volt */
Joe Perchesb46df352010-03-10 15:20:46 -08003923 pr_info("FDC %d is an 82078.\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 return FDC_82078;
3925 case 0x1:
Joe Perchesb46df352010-03-10 15:20:46 -08003926 pr_info("FDC %d is a 44pin 82078\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927 return FDC_82078;
3928 case 0x2:
Joe Perchesb46df352010-03-10 15:20:46 -08003929 pr_info("FDC %d is a S82078B\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930 return FDC_S82078B;
3931 case 0x3:
Joe Perchesb46df352010-03-10 15:20:46 -08003932 pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933 return FDC_87306;
3934 default:
Joe Perchesb46df352010-03-10 15:20:46 -08003935 pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
3936 fdc, reply_buffer[0] >> 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937 return FDC_82078_UNKN;
3938 }
3939} /* get_fdc_version */
3940
3941/* lilo configuration */
3942
3943static void __init floppy_set_flags(int *ints, int param, int param2)
3944{
3945 int i;
3946
3947 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
3948 if (param)
3949 default_drive_params[i].params.flags |= param2;
3950 else
3951 default_drive_params[i].params.flags &= ~param2;
3952 }
3953 DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
3954}
3955
3956static void __init daring(int *ints, int param, int param2)
3957{
3958 int i;
3959
3960 for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
3961 if (param) {
3962 default_drive_params[i].params.select_delay = 0;
3963 default_drive_params[i].params.flags |=
3964 FD_SILENT_DCL_CLEAR;
3965 } else {
3966 default_drive_params[i].params.select_delay =
3967 2 * HZ / 100;
3968 default_drive_params[i].params.flags &=
3969 ~FD_SILENT_DCL_CLEAR;
3970 }
3971 }
3972 DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
3973}
3974
3975static void __init set_cmos(int *ints, int dummy, int dummy2)
3976{
3977 int current_drive = 0;
3978
3979 if (ints[0] != 2) {
3980 DPRINT("wrong number of parameters for CMOS\n");
3981 return;
3982 }
3983 current_drive = ints[1];
3984 if (current_drive < 0 || current_drive >= 8) {
3985 DPRINT("bad drive for set_cmos\n");
3986 return;
3987 }
3988#if N_FDC > 1
3989 if (current_drive >= 4 && !FDC2)
3990 FDC2 = 0x370;
3991#endif
3992 DP->cmos = ints[2];
3993 DPRINT("setting CMOS code to %d\n", ints[2]);
3994}
3995
3996static struct param_table {
3997 const char *name;
3998 void (*fn) (int *ints, int param, int param2);
3999 int *var;
4000 int def_param;
4001 int param2;
4002} config_params[] __initdata = {
4003 {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4004 {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4005 {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4006 {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4007 {"dma", NULL, &FLOPPY_DMA, 2, 0},
4008 {"daring", daring, NULL, 1, 0},
4009#if N_FDC > 1
4010 {"two_fdc", NULL, &FDC2, 0x370, 0},
4011 {"one_fdc", NULL, &FDC2, 0, 0},
4012#endif
4013 {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4014 {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4015 {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4016 {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4017 {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4018 {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4019 {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4020 {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4021 {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4022 {"nofifo", NULL, &no_fifo, 0x20, 0},
4023 {"usefifo", NULL, &no_fifo, 0, 0},
4024 {"cmos", set_cmos, NULL, 0, 0},
4025 {"slow", NULL, &slow_floppy, 1, 0},
4026 {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4027 {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4028 {"L40SX", NULL, &print_unex, 0, 0}
4029
4030 EXTRA_FLOPPY_PARAMS
4031};
4032
4033static int __init floppy_setup(char *str)
4034{
4035 int i;
4036 int param;
4037 int ints[11];
4038
4039 str = get_options(str, ARRAY_SIZE(ints), ints);
4040 if (str) {
4041 for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4042 if (strcmp(str, config_params[i].name) == 0) {
4043 if (ints[0])
4044 param = ints[1];
4045 else
4046 param = config_params[i].def_param;
4047 if (config_params[i].fn)
Joe Perchesbb57f0c2010-03-10 15:20:50 -08004048 config_params[i].fn(ints, param,
4049 config_params[i].
4050 param2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 if (config_params[i].var) {
4052 DPRINT("%s=%d\n", str, param);
4053 *config_params[i].var = param;
4054 }
4055 return 1;
4056 }
4057 }
4058 }
4059 if (str) {
4060 DPRINT("unknown floppy option [%s]\n", str);
4061
4062 DPRINT("allowed options are:");
4063 for (i = 0; i < ARRAY_SIZE(config_params); i++)
Joe Perchesb46df352010-03-10 15:20:46 -08004064 pr_cont(" %s", config_params[i].name);
4065 pr_cont("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066 } else
4067 DPRINT("botched floppy option\n");
Randy Dunlap31c00fc2008-11-13 21:33:24 +00004068 DPRINT("Read Documentation/blockdev/floppy.txt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069 return 0;
4070}
4071
4072static int have_no_fdc = -ENODEV;
4073
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004074static ssize_t floppy_cmos_show(struct device *dev,
4075 struct device_attribute *attr, char *buf)
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004076{
Eric Miao71b3e0c2009-01-31 22:47:44 +08004077 struct platform_device *p = to_platform_device(dev);
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004078 int drive;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004079
Andrew Morton9a8af6b2005-07-27 17:37:34 -07004080 drive = p->id;
4081 return sprintf(buf, "%X\n", UDP->cmos);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004082}
Joe Perches48c8cee2010-03-10 15:20:45 -08004083
Stephen Hemmingerbe1c0fb2010-06-15 13:21:11 +02004084static DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004085
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086static void floppy_device_release(struct device *dev)
4087{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088}
4089
Frans Popc90cd332009-07-25 22:24:54 +02004090static int floppy_resume(struct device *dev)
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004091{
4092 int fdc;
4093
4094 for (fdc = 0; fdc < N_FDC; fdc++)
4095 if (FDCS->address != -1)
Joe Perches74f63f42010-03-10 15:20:58 -08004096 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004097
4098 return 0;
4099}
4100
Alexey Dobriyan47145212009-12-14 18:00:08 -08004101static const struct dev_pm_ops floppy_pm_ops = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004102 .resume = floppy_resume,
Frans Popc90cd332009-07-25 22:24:54 +02004103 .restore = floppy_resume,
4104};
4105
4106static struct platform_driver floppy_driver = {
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004107 .driver = {
Joe Perchesbb57f0c2010-03-10 15:20:50 -08004108 .name = "floppy",
4109 .pm = &floppy_pm_ops,
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004110 },
4111};
4112
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004113static struct platform_device floppy_device[N_DRIVE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114
4115static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4116{
4117 int drive = (*part & 3) | ((*part & 0x80) >> 5);
4118 if (drive >= N_DRIVE ||
4119 !(allowed_drive_mask & (1 << drive)) ||
4120 fdc_state[FDC(drive)].version == FDC_NONE)
4121 return NULL;
Tobias Klauser945f3902006-01-08 01:05:11 -08004122 if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123 return NULL;
4124 *part = 0;
4125 return get_disk(disks[drive]);
4126}
4127
4128static int __init floppy_init(void)
4129{
4130 int i, unit, drive;
4131 int err, dr;
4132
Stephen Hemminger285203c2010-06-15 13:21:11 +02004133 set_debugt();
4134 interruptjiffies = resultjiffies = jiffies;
4135
Kumar Gala68e1ee62008-09-22 14:41:31 -07004136#if defined(CONFIG_PPC)
Olaf Heringef16b512006-08-31 21:27:41 -07004137 if (check_legacy_ioport(FDC1))
4138 return -ENODEV;
4139#endif
4140
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141 raw_cmd = NULL;
4142
4143 for (dr = 0; dr < N_DRIVE; dr++) {
4144 disks[dr] = alloc_disk(1);
4145 if (!disks[dr]) {
4146 err = -ENOMEM;
4147 goto out_put_disk;
4148 }
4149
4150 disks[dr]->major = FLOPPY_MAJOR;
4151 disks[dr]->first_minor = TOMINOR(dr);
4152 disks[dr]->fops = &floppy_fops;
4153 sprintf(disks[dr]->disk_name, "fd%d", dr);
4154
4155 init_timer(&motor_off_timer[dr]);
4156 motor_off_timer[dr].data = dr;
4157 motor_off_timer[dr].function = motor_off_callback;
4158 }
4159
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 err = register_blkdev(FLOPPY_MAJOR, "fd");
4161 if (err)
Greg Kroah-Hartman8ab5e4c2005-06-20 21:15:16 -07004162 goto out_put_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004164 err = platform_driver_register(&floppy_driver);
4165 if (err)
4166 goto out_unreg_blkdev;
4167
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168 floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
4169 if (!floppy_queue) {
4170 err = -ENOMEM;
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004171 goto out_unreg_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172 }
Martin K. Petersen086fa5f2010-02-26 00:20:38 -05004173 blk_queue_max_hw_sectors(floppy_queue, 64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174
4175 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4176 floppy_find, NULL, NULL);
4177
4178 for (i = 0; i < 256; i++)
4179 if (ITYPE(i))
4180 floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4181 else
4182 floppy_sizes[i] = MAX_DISK_SIZE << 1;
4183
Joe Perches73507e62010-03-10 15:21:03 -08004184 reschedule_timeout(MAXTIMEOUT, "floppy init");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185 config_types();
4186
4187 for (i = 0; i < N_FDC; i++) {
4188 fdc = i;
Joe Perchesb87c9e02010-03-10 15:20:50 -08004189 memset(FDCS, 0, sizeof(*FDCS));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 FDCS->dtr = -1;
4191 FDCS->dor = 0x4;
4192#if defined(__sparc__) || defined(__mc68000__)
Joe Perches96534f12010-03-10 15:20:51 -08004193 /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194#ifdef __mc68000__
4195 if (MACH_IS_SUN3X)
4196#endif
4197 FDCS->version = FDC_82072A;
4198#endif
4199 }
4200
4201 use_virtual_dma = can_use_virtual_dma & 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202 fdc_state[0].address = FDC1;
4203 if (fdc_state[0].address == -1) {
4204 del_timer(&fd_timeout);
4205 err = -ENODEV;
4206 goto out_unreg_region;
4207 }
4208#if N_FDC > 1
4209 fdc_state[1].address = FDC2;
4210#endif
4211
4212 fdc = 0; /* reset fdc in case of unexpected interrupt */
4213 err = floppy_grab_irq_and_dma();
4214 if (err) {
4215 del_timer(&fd_timeout);
4216 err = -EBUSY;
4217 goto out_unreg_region;
4218 }
4219
4220 /* initialise drive state */
4221 for (drive = 0; drive < N_DRIVE; drive++) {
Joe Perchesb87c9e02010-03-10 15:20:50 -08004222 memset(UDRS, 0, sizeof(*UDRS));
4223 memset(UDRWE, 0, sizeof(*UDRWE));
Joe Perchese0298532010-03-10 15:20:55 -08004224 set_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
4225 set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
4226 set_bit(FD_VERIFY_BIT, &UDRS->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 UDRS->fd_device = -1;
4228 floppy_track_buffer = NULL;
4229 max_buffer_sectors = 0;
4230 }
4231 /*
4232 * Small 10 msec delay to let through any interrupt that
4233 * initialization might have triggered, to not
4234 * confuse detection:
4235 */
4236 msleep(10);
4237
4238 for (i = 0; i < N_FDC; i++) {
4239 fdc = i;
4240 FDCS->driver_version = FD_DRIVER_VERSION;
4241 for (unit = 0; unit < 4; unit++)
4242 FDCS->track[unit] = 0;
4243 if (FDCS->address == -1)
4244 continue;
4245 FDCS->rawcmd = 2;
Joe Perches74f63f42010-03-10 15:20:58 -08004246 if (user_reset_fdc(-1, FD_RESET_ALWAYS, false)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004248 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249 FDCS->address = -1;
4250 FDCS->version = FDC_NONE;
4251 continue;
4252 }
4253 /* Try to determine the floppy controller type */
4254 FDCS->version = get_fdc_version();
4255 if (FDCS->version == FDC_NONE) {
4256 /* free ioports reserved by floppy_grab_irq_and_dma() */
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004257 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 FDCS->address = -1;
4259 continue;
4260 }
4261 if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
4262 can_use_virtual_dma = 0;
4263
4264 have_no_fdc = 0;
4265 /* Not all FDCs seem to be able to handle the version command
4266 * properly, so force a reset for the standard FDC clones,
4267 * to avoid interrupt garbage.
4268 */
Joe Perches74f63f42010-03-10 15:20:58 -08004269 user_reset_fdc(-1, FD_RESET_ALWAYS, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 }
4271 fdc = 0;
4272 del_timer(&fd_timeout);
4273 current_drive = 0;
Joe Perches29f1c782010-03-10 15:21:00 -08004274 initialized = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275 if (have_no_fdc) {
4276 DPRINT("no floppy controllers found\n");
4277 err = have_no_fdc;
4278 goto out_flush_work;
4279 }
4280
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 for (drive = 0; drive < N_DRIVE; drive++) {
4282 if (!(allowed_drive_mask & (1 << drive)))
4283 continue;
4284 if (fdc_state[FDC(drive)].version == FDC_NONE)
4285 continue;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004286
4287 floppy_device[drive].name = floppy_device_name;
4288 floppy_device[drive].id = drive;
4289 floppy_device[drive].dev.release = floppy_device_release;
4290
4291 err = platform_device_register(&floppy_device[drive]);
4292 if (err)
4293 goto out_flush_work;
4294
Joe Perchesd7b2b2e2010-03-10 15:20:48 -08004295 err = device_create_file(&floppy_device[drive].dev,
4296 &dev_attr_cmos);
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004297 if (err)
4298 goto out_unreg_platform_dev;
4299
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300 /* to be cleaned up... */
4301 disks[drive]->private_data = (void *)(long)drive;
4302 disks[drive]->queue = floppy_queue;
4303 disks[drive]->flags |= GENHD_FL_REMOVABLE;
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004304 disks[drive]->driverfs_dev = &floppy_device[drive].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 add_disk(disks[drive]);
4306 }
4307
4308 return 0;
4309
Dmitriy Monakhov4ea1b0f2007-05-08 00:25:58 -07004310out_unreg_platform_dev:
4311 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312out_flush_work:
4313 flush_scheduled_work();
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004314 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315 floppy_release_irq_and_dma();
4316out_unreg_region:
4317 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4318 blk_cleanup_queue(floppy_queue);
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004319out_unreg_driver:
4320 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321out_unreg_blkdev:
4322 unregister_blkdev(FLOPPY_MAJOR, "fd");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323out_put_disk:
4324 while (dr--) {
4325 del_timer(&motor_off_timer[dr]);
4326 put_disk(disks[dr]);
4327 }
4328 return err;
4329}
4330
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004331static const struct io_region {
4332 int offset;
4333 int size;
4334} io_regions[] = {
4335 { 2, 1 },
4336 /* address + 3 is sometimes reserved by pnp bios for motherboard */
4337 { 4, 2 },
4338 /* address + 6 is reserved, and may be taken by IDE.
4339 * Unfortunately, Adaptec doesn't know this :-(, */
4340 { 7, 1 },
4341};
4342
4343static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4344{
4345 while (p != io_regions) {
4346 p--;
4347 release_region(FDCS->address + p->offset, p->size);
4348 }
4349}
4350
4351#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4352
4353static int floppy_request_regions(int fdc)
4354{
4355 const struct io_region *p;
4356
4357 for (p = io_regions; p < ARRAY_END(io_regions); p++) {
Joe Perchesbb57f0c2010-03-10 15:20:50 -08004358 if (!request_region(FDCS->address + p->offset,
4359 p->size, "floppy")) {
4360 DPRINT("Floppy io-port 0x%04lx in use\n",
4361 FDCS->address + p->offset);
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004362 floppy_release_allocated_regions(fdc, p);
4363 return -EBUSY;
4364 }
4365 }
4366 return 0;
4367}
4368
4369static void floppy_release_regions(int fdc)
4370{
4371 floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4372}
4373
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374static int floppy_grab_irq_and_dma(void)
4375{
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004376 if (atomic_inc_return(&usage_count) > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 return 0;
Ingo Molnar6dc659d2006-03-26 01:36:54 -08004378
4379 /*
4380 * We might have scheduled a free_irq(), wait it to
4381 * drain first:
4382 */
4383 flush_scheduled_work();
4384
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385 if (fd_request_irq()) {
4386 DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4387 FLOPPY_IRQ);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004388 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389 return -1;
4390 }
4391 if (fd_request_dma()) {
4392 DPRINT("Unable to grab DMA%d for the floppy driver\n",
4393 FLOPPY_DMA);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004394 if (can_use_virtual_dma & 2)
4395 use_virtual_dma = can_use_virtual_dma = 1;
4396 if (!(can_use_virtual_dma & 1)) {
4397 fd_free_irq();
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004398 atomic_dec(&usage_count);
Jan Beulich2e9c47c2007-10-16 23:27:32 -07004399 return -1;
4400 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401 }
4402
4403 for (fdc = 0; fdc < N_FDC; fdc++) {
4404 if (FDCS->address != -1) {
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004405 if (floppy_request_regions(fdc))
4406 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407 }
4408 }
4409 for (fdc = 0; fdc < N_FDC; fdc++) {
4410 if (FDCS->address != -1) {
4411 reset_fdc_info(1);
4412 fd_outb(FDCS->dor, FD_DOR);
4413 }
4414 }
4415 fdc = 0;
4416 set_dor(0, ~0, 8); /* avoid immediate interrupt */
4417
4418 for (fdc = 0; fdc < N_FDC; fdc++)
4419 if (FDCS->address != -1)
4420 fd_outb(FDCS->dor, FD_DOR);
4421 /*
Jesper Juhl06f748c2007-10-16 23:30:57 -07004422 * The driver will try and free resources and relies on us
4423 * to know if they were allocated or not.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 */
4425 fdc = 0;
4426 irqdma_allocated = 1;
4427 return 0;
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004428cleanup:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 fd_free_irq();
4430 fd_free_dma();
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004431 while (--fdc >= 0)
4432 floppy_release_regions(fdc);
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004433 atomic_dec(&usage_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 return -1;
4435}
4436
4437static void floppy_release_irq_and_dma(void)
4438{
4439 int old_fdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440#ifndef __sparc__
4441 int drive;
4442#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 long tmpsize;
4444 unsigned long tmpaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004446 if (!atomic_dec_and_test(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 return;
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004448
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449 if (irqdma_allocated) {
4450 fd_disable_dma();
4451 fd_free_dma();
Ingo Molnar3e541a42006-07-03 00:24:23 -07004452 fd_free_irq();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453 irqdma_allocated = 0;
4454 }
4455 set_dor(0, ~0, 8);
4456#if N_FDC > 1
4457 set_dor(1, ~8, 0);
4458#endif
4459 floppy_enable_hlt();
4460
4461 if (floppy_track_buffer && max_buffer_sectors) {
4462 tmpsize = max_buffer_sectors * 1024;
4463 tmpaddr = (unsigned long)floppy_track_buffer;
4464 floppy_track_buffer = NULL;
4465 max_buffer_sectors = 0;
4466 buffer_min = buffer_max = -1;
4467 fd_dma_mem_free(tmpaddr, tmpsize);
4468 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469#ifndef __sparc__
4470 for (drive = 0; drive < N_FDC * 4; drive++)
4471 if (timer_pending(motor_off_timer + drive))
Joe Perchesb46df352010-03-10 15:20:46 -08004472 pr_info("motor off timer %d still active\n", drive);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473#endif
4474
4475 if (timer_pending(&fd_timeout))
Joe Perchesb46df352010-03-10 15:20:46 -08004476 pr_info("floppy timer still active:%s\n", timeout_message);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 if (timer_pending(&fd_timer))
Joe Perchesb46df352010-03-10 15:20:46 -08004478 pr_info("auxiliary floppy timer still active\n");
David Howells365970a2006-11-22 14:54:49 +00004479 if (work_pending(&floppy_work))
Joe Perchesb46df352010-03-10 15:20:46 -08004480 pr_info("work still pending\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 old_fdc = fdc;
4482 for (fdc = 0; fdc < N_FDC; fdc++)
Philippe De Muyter5a74db02009-02-18 14:48:36 -08004483 if (FDCS->address != -1)
4484 floppy_release_regions(fdc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 fdc = old_fdc;
4486}
4487
4488#ifdef MODULE
4489
4490static char *floppy;
4491
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492static void __init parse_floppy_cfg_string(char *cfg)
4493{
4494 char *ptr;
4495
4496 while (*cfg) {
Joe Perchesbb57f0c2010-03-10 15:20:50 -08004497 ptr = cfg;
4498 while (*cfg && *cfg != ' ' && *cfg != '\t')
4499 cfg++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500 if (*cfg) {
4501 *cfg = '\0';
4502 cfg++;
4503 }
4504 if (*ptr)
4505 floppy_setup(ptr);
4506 }
4507}
4508
Jon Schindler7afea3b2008-04-29 00:59:21 -07004509static int __init floppy_module_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510{
4511 if (floppy)
4512 parse_floppy_cfg_string(floppy);
4513 return floppy_init();
4514}
Jon Schindler7afea3b2008-04-29 00:59:21 -07004515module_init(floppy_module_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516
Jon Schindler7afea3b2008-04-29 00:59:21 -07004517static void __exit floppy_module_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518{
4519 int drive;
4520
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4522 unregister_blkdev(FLOPPY_MAJOR, "fd");
Ondrej Zary5e50b9e2009-06-10 12:57:09 -07004523 platform_driver_unregister(&floppy_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524
4525 for (drive = 0; drive < N_DRIVE; drive++) {
4526 del_timer_sync(&motor_off_timer[drive]);
4527
4528 if ((allowed_drive_mask & (1 << drive)) &&
4529 fdc_state[FDC(drive)].version != FDC_NONE) {
4530 del_gendisk(disks[drive]);
Hannes Reinecke94fd0db2005-07-15 10:09:25 +02004531 device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
4532 platform_device_unregister(&floppy_device[drive]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533 }
4534 put_disk(disks[drive]);
4535 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536
4537 del_timer_sync(&fd_timeout);
4538 del_timer_sync(&fd_timer);
4539 blk_cleanup_queue(floppy_queue);
4540
Stephen Hemminger575cfc62010-06-15 13:21:11 +02004541 if (atomic_read(&usage_count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 floppy_release_irq_and_dma();
4543
4544 /* eject disk, if any */
4545 fd_eject(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546}
Joe Perches48c8cee2010-03-10 15:20:45 -08004547
Jon Schindler7afea3b2008-04-29 00:59:21 -07004548module_exit(floppy_module_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549
4550module_param(floppy, charp, 0);
4551module_param(FLOPPY_IRQ, int, 0);
4552module_param(FLOPPY_DMA, int, 0);
4553MODULE_AUTHOR("Alain L. Knaff");
4554MODULE_SUPPORTED_DEVICE("fd");
4555MODULE_LICENSE("GPL");
4556
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004557/* This doesn't actually get used other than for module information */
4558static const struct pnp_device_id floppy_pnpids[] = {
Joe Perches48c8cee2010-03-10 15:20:45 -08004559 {"PNP0700", 0},
4560 {}
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004561};
Joe Perches48c8cee2010-03-10 15:20:45 -08004562
Scott James Remnant83f9ef42009-04-02 16:56:47 -07004563MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
4564
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565#else
4566
4567__setup("floppy=", floppy_setup);
4568module_init(floppy_init)
4569#endif
4570
4571MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);