1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * linux/drivers/block/floppy.c
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 1991, 1992 Linus Torvalds
6*4882a593Smuzhiyun * Copyright (C) 1993, 1994 Alain Knaff
7*4882a593Smuzhiyun * Copyright (C) 1998 Alan Cox
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun /*
11*4882a593Smuzhiyun * 02.12.91 - Changed to static variables to indicate need for reset
12*4882a593Smuzhiyun * and recalibrate. This makes some things easier (output_byte reset
13*4882a593Smuzhiyun * checking etc), and means less interrupt jumping in case of errors,
14*4882a593Smuzhiyun * so the code is hopefully easier to understand.
15*4882a593Smuzhiyun */
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun /*
18*4882a593Smuzhiyun * This file is certainly a mess. I've tried my best to get it working,
19*4882a593Smuzhiyun * but I don't like programming floppies, and I have only one anyway.
20*4882a593Smuzhiyun * Urgel. I should check for more errors, and do more graceful error
21*4882a593Smuzhiyun * recovery. Seems there are problems with several drives. I've tried to
22*4882a593Smuzhiyun * correct them. No promises.
23*4882a593Smuzhiyun */
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun /*
26*4882a593Smuzhiyun * As with hd.c, all routines within this file can (and will) be called
27*4882a593Smuzhiyun * by interrupts, so extreme caution is needed. A hardware interrupt
28*4882a593Smuzhiyun * handler may not sleep, or a kernel panic will happen. Thus I cannot
29*4882a593Smuzhiyun * call "floppy-on" directly, but have to set a special timer interrupt
30*4882a593Smuzhiyun * etc.
31*4882a593Smuzhiyun */
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun /*
34*4882a593Smuzhiyun * 28.02.92 - made track-buffering routines, based on the routines written
35*4882a593Smuzhiyun * by entropy@wintermute.wpi.edu (Lawrence Foard). Linus.
36*4882a593Smuzhiyun */
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun /*
39*4882a593Smuzhiyun * Automatic floppy-detection and formatting written by Werner Almesberger
40*4882a593Smuzhiyun * (almesber@nessie.cs.id.ethz.ch), who also corrected some problems with
41*4882a593Smuzhiyun * the floppy-change signal detection.
42*4882a593Smuzhiyun */
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun /*
45*4882a593Smuzhiyun * 1992/7/22 -- Hennus Bergman: Added better error reporting, fixed
46*4882a593Smuzhiyun * FDC data overrun bug, added some preliminary stuff for vertical
47*4882a593Smuzhiyun * recording support.
48*4882a593Smuzhiyun *
49*4882a593Smuzhiyun * 1992/9/17: Added DMA allocation & DMA functions. -- hhb.
50*4882a593Smuzhiyun *
51*4882a593Smuzhiyun * TODO: Errors are still not counted properly.
52*4882a593Smuzhiyun */
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun /* 1992/9/20
55*4882a593Smuzhiyun * Modifications for ``Sector Shifting'' by Rob Hooft (hooft@chem.ruu.nl)
56*4882a593Smuzhiyun * modeled after the freeware MS-DOS program fdformat/88 V1.8 by
57*4882a593Smuzhiyun * Christoph H. Hochst\"atter.
58*4882a593Smuzhiyun * I have fixed the shift values to the ones I always use. Maybe a new
59*4882a593Smuzhiyun * ioctl() should be created to be able to modify them.
60*4882a593Smuzhiyun * There is a bug in the driver that makes it impossible to format a
61*4882a593Smuzhiyun * floppy as the first thing after bootup.
62*4882a593Smuzhiyun */
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun /*
65*4882a593Smuzhiyun * 1993/4/29 -- Linus -- cleaned up the timer handling in the kernel, and
66*4882a593Smuzhiyun * this helped the floppy driver as well. Much cleaner, and still seems to
67*4882a593Smuzhiyun * work.
68*4882a593Smuzhiyun */
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun /* 1994/6/24 --bbroad-- added the floppy table entries and made
71*4882a593Smuzhiyun * minor modifications to allow 2.88 floppies to be run.
72*4882a593Smuzhiyun */
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun /* 1994/7/13 -- Paul Vojta -- modified the probing code to allow three or more
75*4882a593Smuzhiyun * disk types.
76*4882a593Smuzhiyun */
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun /*
79*4882a593Smuzhiyun * 1994/8/8 -- Alain Knaff -- Switched to fdpatch driver: Support for bigger
80*4882a593Smuzhiyun * format bug fixes, but unfortunately some new bugs too...
81*4882a593Smuzhiyun */
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun /* 1994/9/17 -- Koen Holtman -- added logging of physical floppy write
84*4882a593Smuzhiyun * errors to allow safe writing by specialized programs.
85*4882a593Smuzhiyun */
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun /* 1995/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks
88*4882a593Smuzhiyun * by defining bit 1 of the "stretch" parameter to mean put sectors on the
89*4882a593Smuzhiyun * opposite side of the disk, leaving the sector IDs alone (i.e. Commodore's
90*4882a593Smuzhiyun * drives are "upside-down").
91*4882a593Smuzhiyun */
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun /*
94*4882a593Smuzhiyun * 1995/8/26 -- Andreas Busse -- added Mips support.
95*4882a593Smuzhiyun */
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun /*
98*4882a593Smuzhiyun * 1995/10/18 -- Ralf Baechle -- Portability cleanup; move machine dependent
99*4882a593Smuzhiyun * features to asm/floppy.h.
100*4882a593Smuzhiyun */
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun /*
103*4882a593Smuzhiyun * 1998/1/21 -- Richard Gooch <rgooch@atnf.csiro.au> -- devfs support
104*4882a593Smuzhiyun */
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun /*
107*4882a593Smuzhiyun * 1998/05/07 -- Russell King -- More portability cleanups; moved definition of
108*4882a593Smuzhiyun * interrupt and dma channel to asm/floppy.h. Cleaned up some formatting &
109*4882a593Smuzhiyun * use of '0' for NULL.
110*4882a593Smuzhiyun */
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun /*
113*4882a593Smuzhiyun * 1998/06/07 -- Alan Cox -- Merged the 2.0.34 fixes for resource allocation
114*4882a593Smuzhiyun * failures.
115*4882a593Smuzhiyun */
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun /*
118*4882a593Smuzhiyun * 1998/09/20 -- David Weinehall -- Added slow-down code for buggy PS/2-drives.
119*4882a593Smuzhiyun */
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun /*
122*4882a593Smuzhiyun * 1999/08/13 -- Paul Slootman -- floppy stopped working on Alpha after 24
123*4882a593Smuzhiyun * days, 6 hours, 32 minutes and 32 seconds (i.e. MAXINT jiffies; ints were
124*4882a593Smuzhiyun * being used to store jiffies, which are unsigned longs).
125*4882a593Smuzhiyun */
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun /*
128*4882a593Smuzhiyun * 2000/08/28 -- Arnaldo Carvalho de Melo <acme@conectiva.com.br>
129*4882a593Smuzhiyun * - get rid of check_region
130*4882a593Smuzhiyun * - s/suser/capable/
131*4882a593Smuzhiyun */
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun /*
134*4882a593Smuzhiyun * 2001/08/26 -- Paul Gortmaker - fix insmod oops on machines with no
135*4882a593Smuzhiyun * floppy controller (lingering task on list after module is gone... boom.)
136*4882a593Smuzhiyun */
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun /*
139*4882a593Smuzhiyun * 2002/02/07 -- Anton Altaparmakov - Fix io ports reservation to correct range
140*4882a593Smuzhiyun * (0x3f2-0x3f5, 0x3f7). This fix is a bit of a hack but the proper fix
141*4882a593Smuzhiyun * requires many non-obvious changes in arch dependent code.
142*4882a593Smuzhiyun */
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun /* 2003/07/28 -- Daniele Bellucci <bellucda@tiscali.it>.
145*4882a593Smuzhiyun * Better audit of register_blkdev.
146*4882a593Smuzhiyun */
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun #undef FLOPPY_SILENT_DCL_CLEAR
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun #define REALLY_SLOW_IO
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun #define DEBUGT 2
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun #define DPRINT(format, args...) \
155*4882a593Smuzhiyun pr_info("floppy%d: " format, current_drive, ##args)
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun #define DCL_DEBUG /* debug disk change line */
158*4882a593Smuzhiyun #ifdef DCL_DEBUG
159*4882a593Smuzhiyun #define debug_dcl(test, fmt, args...) \
160*4882a593Smuzhiyun do { if ((test) & FD_DEBUG) DPRINT(fmt, ##args); } while (0)
161*4882a593Smuzhiyun #else
162*4882a593Smuzhiyun #define debug_dcl(test, fmt, args...) \
163*4882a593Smuzhiyun do { if (0) DPRINT(fmt, ##args); } while (0)
164*4882a593Smuzhiyun #endif
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun /* do print messages for unexpected interrupts */
167*4882a593Smuzhiyun static int print_unex = 1;
168*4882a593Smuzhiyun #include <linux/module.h>
169*4882a593Smuzhiyun #include <linux/sched.h>
170*4882a593Smuzhiyun #include <linux/fs.h>
171*4882a593Smuzhiyun #include <linux/kernel.h>
172*4882a593Smuzhiyun #include <linux/timer.h>
173*4882a593Smuzhiyun #include <linux/workqueue.h>
174*4882a593Smuzhiyun #include <linux/fdreg.h>
175*4882a593Smuzhiyun #include <linux/fd.h>
176*4882a593Smuzhiyun #include <linux/hdreg.h>
177*4882a593Smuzhiyun #include <linux/errno.h>
178*4882a593Smuzhiyun #include <linux/slab.h>
179*4882a593Smuzhiyun #include <linux/mm.h>
180*4882a593Smuzhiyun #include <linux/bio.h>
181*4882a593Smuzhiyun #include <linux/string.h>
182*4882a593Smuzhiyun #include <linux/jiffies.h>
183*4882a593Smuzhiyun #include <linux/fcntl.h>
184*4882a593Smuzhiyun #include <linux/delay.h>
185*4882a593Smuzhiyun #include <linux/mc146818rtc.h> /* CMOS defines */
186*4882a593Smuzhiyun #include <linux/ioport.h>
187*4882a593Smuzhiyun #include <linux/interrupt.h>
188*4882a593Smuzhiyun #include <linux/init.h>
189*4882a593Smuzhiyun #include <linux/platform_device.h>
190*4882a593Smuzhiyun #include <linux/mod_devicetable.h>
191*4882a593Smuzhiyun #include <linux/mutex.h>
192*4882a593Smuzhiyun #include <linux/io.h>
193*4882a593Smuzhiyun #include <linux/uaccess.h>
194*4882a593Smuzhiyun #include <linux/async.h>
195*4882a593Smuzhiyun #include <linux/compat.h>
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun /*
198*4882a593Smuzhiyun * PS/2 floppies have much slower step rates than regular floppies.
199*4882a593Smuzhiyun * It's been recommended that take about 1/4 of the default speed
200*4882a593Smuzhiyun * in some more extreme cases.
201*4882a593Smuzhiyun */
202*4882a593Smuzhiyun static DEFINE_MUTEX(floppy_mutex);
203*4882a593Smuzhiyun static int slow_floppy;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun #include <asm/dma.h>
206*4882a593Smuzhiyun #include <asm/irq.h>
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun static int FLOPPY_IRQ = 6;
209*4882a593Smuzhiyun static int FLOPPY_DMA = 2;
210*4882a593Smuzhiyun static int can_use_virtual_dma = 2;
211*4882a593Smuzhiyun /* =======
212*4882a593Smuzhiyun * can use virtual DMA:
213*4882a593Smuzhiyun * 0 = use of virtual DMA disallowed by config
214*4882a593Smuzhiyun * 1 = use of virtual DMA prescribed by config
215*4882a593Smuzhiyun * 2 = no virtual DMA preference configured. By default try hard DMA,
216*4882a593Smuzhiyun * but fall back on virtual DMA when not enough memory available
217*4882a593Smuzhiyun */
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun static int use_virtual_dma;
220*4882a593Smuzhiyun /* =======
221*4882a593Smuzhiyun * use virtual DMA
222*4882a593Smuzhiyun * 0 using hard DMA
223*4882a593Smuzhiyun * 1 using virtual DMA
224*4882a593Smuzhiyun * This variable is set to virtual when a DMA mem problem arises, and
225*4882a593Smuzhiyun * reset back in floppy_grab_irq_and_dma.
226*4882a593Smuzhiyun * It is not safe to reset it in other circumstances, because the floppy
227*4882a593Smuzhiyun * driver may have several buffers in use at once, and we do currently not
228*4882a593Smuzhiyun * record each buffers capabilities
229*4882a593Smuzhiyun */
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun static DEFINE_SPINLOCK(floppy_lock);
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun static unsigned short virtual_dma_port = 0x3f0;
234*4882a593Smuzhiyun irqreturn_t floppy_interrupt(int irq, void *dev_id);
235*4882a593Smuzhiyun static int set_dor(int fdc, char mask, char data);
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun #define K_64 0x10000 /* 64KB */
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun /* the following is the mask of allowed drives. By default units 2 and
240*4882a593Smuzhiyun * 3 of both floppy controllers are disabled, because switching on the
241*4882a593Smuzhiyun * motor of these drives causes system hangs on some PCI computers. drive
242*4882a593Smuzhiyun * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
243*4882a593Smuzhiyun * a drive is allowed.
244*4882a593Smuzhiyun *
245*4882a593Smuzhiyun * NOTE: This must come before we include the arch floppy header because
246*4882a593Smuzhiyun * some ports reference this variable from there. -DaveM
247*4882a593Smuzhiyun */
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun static int allowed_drive_mask = 0x33;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun #include <asm/floppy.h>
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun static int irqdma_allocated;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun #include <linux/blk-mq.h>
256*4882a593Smuzhiyun #include <linux/blkpg.h>
257*4882a593Smuzhiyun #include <linux/cdrom.h> /* for the compatibility eject ioctl */
258*4882a593Smuzhiyun #include <linux/completion.h>
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun static LIST_HEAD(floppy_reqs);
261*4882a593Smuzhiyun static struct request *current_req;
262*4882a593Smuzhiyun static int set_next_request(void);
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun #ifndef fd_get_dma_residue
265*4882a593Smuzhiyun #define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
266*4882a593Smuzhiyun #endif
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun /* Dma Memory related stuff */
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun #ifndef fd_dma_mem_free
271*4882a593Smuzhiyun #define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size))
272*4882a593Smuzhiyun #endif
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun #ifndef fd_dma_mem_alloc
275*4882a593Smuzhiyun #define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL, get_order(size))
276*4882a593Smuzhiyun #endif
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun #ifndef fd_cacheflush
279*4882a593Smuzhiyun #define fd_cacheflush(addr, size) /* nothing... */
280*4882a593Smuzhiyun #endif
281*4882a593Smuzhiyun
fallback_on_nodma_alloc(char ** addr,size_t l)282*4882a593Smuzhiyun static inline void fallback_on_nodma_alloc(char **addr, size_t l)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun #ifdef FLOPPY_CAN_FALLBACK_ON_NODMA
285*4882a593Smuzhiyun if (*addr)
286*4882a593Smuzhiyun return; /* we have the memory */
287*4882a593Smuzhiyun if (can_use_virtual_dma != 2)
288*4882a593Smuzhiyun return; /* no fallback allowed */
289*4882a593Smuzhiyun pr_info("DMA memory shortage. Temporarily falling back on virtual DMA\n");
290*4882a593Smuzhiyun *addr = (char *)nodma_mem_alloc(l);
291*4882a593Smuzhiyun #else
292*4882a593Smuzhiyun return;
293*4882a593Smuzhiyun #endif
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun /* End dma memory related stuff */
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun static unsigned long fake_change;
299*4882a593Smuzhiyun static bool initialized;
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun #define ITYPE(x) (((x) >> 2) & 0x1f)
302*4882a593Smuzhiyun #define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
303*4882a593Smuzhiyun #define UNIT(x) ((x) & 0x03) /* drive on fdc */
304*4882a593Smuzhiyun #define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */
305*4882a593Smuzhiyun /* reverse mapping from unit and fdc to drive */
306*4882a593Smuzhiyun #define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun #define PH_HEAD(floppy, head) (((((floppy)->stretch & 2) >> 1) ^ head) << 2)
309*4882a593Smuzhiyun #define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun /* read/write commands */
312*4882a593Smuzhiyun #define COMMAND 0
313*4882a593Smuzhiyun #define DR_SELECT 1
314*4882a593Smuzhiyun #define TRACK 2
315*4882a593Smuzhiyun #define HEAD 3
316*4882a593Smuzhiyun #define SECTOR 4
317*4882a593Smuzhiyun #define SIZECODE 5
318*4882a593Smuzhiyun #define SECT_PER_TRACK 6
319*4882a593Smuzhiyun #define GAP 7
320*4882a593Smuzhiyun #define SIZECODE2 8
321*4882a593Smuzhiyun #define NR_RW 9
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun /* format commands */
324*4882a593Smuzhiyun #define F_SIZECODE 2
325*4882a593Smuzhiyun #define F_SECT_PER_TRACK 3
326*4882a593Smuzhiyun #define F_GAP 4
327*4882a593Smuzhiyun #define F_FILL 5
328*4882a593Smuzhiyun #define NR_F 6
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun /*
331*4882a593Smuzhiyun * Maximum disk size (in kilobytes).
332*4882a593Smuzhiyun * This default is used whenever the current disk size is unknown.
333*4882a593Smuzhiyun * [Now it is rather a minimum]
334*4882a593Smuzhiyun */
335*4882a593Smuzhiyun #define MAX_DISK_SIZE 4 /* 3984 */
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun /*
338*4882a593Smuzhiyun * globals used by 'result()'
339*4882a593Smuzhiyun */
340*4882a593Smuzhiyun static unsigned char reply_buffer[FD_RAW_REPLY_SIZE];
341*4882a593Smuzhiyun static int inr; /* size of reply buffer, when called from interrupt */
342*4882a593Smuzhiyun #define ST0 0
343*4882a593Smuzhiyun #define ST1 1
344*4882a593Smuzhiyun #define ST2 2
345*4882a593Smuzhiyun #define ST3 0 /* result of GETSTATUS */
346*4882a593Smuzhiyun #define R_TRACK 3
347*4882a593Smuzhiyun #define R_HEAD 4
348*4882a593Smuzhiyun #define R_SECTOR 5
349*4882a593Smuzhiyun #define R_SIZECODE 6
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun #define SEL_DLY (2 * HZ / 100)
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun /*
354*4882a593Smuzhiyun * this struct defines the different floppy drive types.
355*4882a593Smuzhiyun */
356*4882a593Smuzhiyun static struct {
357*4882a593Smuzhiyun struct floppy_drive_params params;
358*4882a593Smuzhiyun const char *name; /* name printed while booting */
359*4882a593Smuzhiyun } default_drive_params[] = {
360*4882a593Smuzhiyun /* NOTE: the time values in jiffies should be in msec!
361*4882a593Smuzhiyun CMOS drive type
362*4882a593Smuzhiyun | Maximum data rate supported by drive type
363*4882a593Smuzhiyun | | Head load time, msec
364*4882a593Smuzhiyun | | | Head unload time, msec (not used)
365*4882a593Smuzhiyun | | | | Step rate interval, usec
366*4882a593Smuzhiyun | | | | | Time needed for spinup time (jiffies)
367*4882a593Smuzhiyun | | | | | | Timeout for spinning down (jiffies)
368*4882a593Smuzhiyun | | | | | | | Spindown offset (where disk stops)
369*4882a593Smuzhiyun | | | | | | | | Select delay
370*4882a593Smuzhiyun | | | | | | | | | RPS
371*4882a593Smuzhiyun | | | | | | | | | | Max number of tracks
372*4882a593Smuzhiyun | | | | | | | | | | | Interrupt timeout
373*4882a593Smuzhiyun | | | | | | | | | | | | Max nonintlv. sectors
374*4882a593Smuzhiyun | | | | | | | | | | | | | -Max Errors- flags */
375*4882a593Smuzhiyun {{0, 500, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 80, 3*HZ, 20, {3,1,2,0,2}, 0,
376*4882a593Smuzhiyun 0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun {{1, 300, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 40, 3*HZ, 17, {3,1,2,0,2}, 0,
379*4882a593Smuzhiyun 0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun {{2, 500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0,
382*4882a593Smuzhiyun 0, { 2, 5, 6,23,10,20,12, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun {{3, 250, 16, 16, 3000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
385*4882a593Smuzhiyun 0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun {{4, 500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
388*4882a593Smuzhiyun 0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun {{5, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
391*4882a593Smuzhiyun 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun {{6, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
394*4882a593Smuzhiyun 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*/
395*4882a593Smuzhiyun /* | --autodetected formats--- | | |
396*4882a593Smuzhiyun * read_track | | Name printed when booting
397*4882a593Smuzhiyun * | Native format
398*4882a593Smuzhiyun * Frequency of disk change checks */
399*4882a593Smuzhiyun };
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun static struct floppy_drive_params drive_params[N_DRIVE];
402*4882a593Smuzhiyun static struct floppy_drive_struct drive_state[N_DRIVE];
403*4882a593Smuzhiyun static struct floppy_write_errors write_errors[N_DRIVE];
404*4882a593Smuzhiyun static struct timer_list motor_off_timer[N_DRIVE];
405*4882a593Smuzhiyun static struct gendisk *disks[N_DRIVE];
406*4882a593Smuzhiyun static struct blk_mq_tag_set tag_sets[N_DRIVE];
407*4882a593Smuzhiyun static struct block_device *opened_bdev[N_DRIVE];
408*4882a593Smuzhiyun static DEFINE_MUTEX(open_lock);
409*4882a593Smuzhiyun static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun /*
412*4882a593Smuzhiyun * This struct defines the different floppy types.
413*4882a593Smuzhiyun *
414*4882a593Smuzhiyun * Bit 0 of 'stretch' tells if the tracks need to be doubled for some
415*4882a593Smuzhiyun * types (e.g. 360kB diskette in 1.2MB drive, etc.). Bit 1 of 'stretch'
416*4882a593Smuzhiyun * tells if the disk is in Commodore 1581 format, which means side 0 sectors
417*4882a593Smuzhiyun * are located on side 1 of the disk but with a side 0 ID, and vice-versa.
418*4882a593Smuzhiyun * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the
419*4882a593Smuzhiyun * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical
420*4882a593Smuzhiyun * side 0 is on physical side 0 (but with the misnamed sector IDs).
421*4882a593Smuzhiyun * 'stretch' should probably be renamed to something more general, like
422*4882a593Smuzhiyun * 'options'.
423*4882a593Smuzhiyun *
424*4882a593Smuzhiyun * Bits 2 through 9 of 'stretch' tell the number of the first sector.
425*4882a593Smuzhiyun * The LSB (bit 2) is flipped. For most disks, the first sector
426*4882a593Smuzhiyun * is 1 (represented by 0x00<<2). For some CP/M and music sampler
427*4882a593Smuzhiyun * disks (such as Ensoniq EPS 16plus) it is 0 (represented as 0x01<<2).
428*4882a593Smuzhiyun * For Amstrad CPC disks it is 0xC1 (represented as 0xC0<<2).
429*4882a593Smuzhiyun *
430*4882a593Smuzhiyun * Other parameters should be self-explanatory (see also setfdprm(8)).
431*4882a593Smuzhiyun */
432*4882a593Smuzhiyun /*
433*4882a593Smuzhiyun Size
434*4882a593Smuzhiyun | Sectors per track
435*4882a593Smuzhiyun | | Head
436*4882a593Smuzhiyun | | | Tracks
437*4882a593Smuzhiyun | | | | Stretch
438*4882a593Smuzhiyun | | | | | Gap 1 size
439*4882a593Smuzhiyun | | | | | | Data rate, | 0x40 for perp
440*4882a593Smuzhiyun | | | | | | | Spec1 (stepping rate, head unload
441*4882a593Smuzhiyun | | | | | | | | /fmt gap (gap2) */
442*4882a593Smuzhiyun static struct floppy_struct floppy_type[32] = {
443*4882a593Smuzhiyun { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* 0 no testing */
444*4882a593Smuzhiyun { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360" }, /* 1 360KB PC */
445*4882a593Smuzhiyun { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" }, /* 2 1.2MB AT */
446*4882a593Smuzhiyun { 720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360" }, /* 3 360KB SS 3.5" */
447*4882a593Smuzhiyun { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720" }, /* 4 720KB 3.5" */
448*4882a593Smuzhiyun { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360" }, /* 5 360KB AT */
449*4882a593Smuzhiyun { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" }, /* 6 720KB AT */
450*4882a593Smuzhiyun { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /* 7 1.44MB 3.5" */
451*4882a593Smuzhiyun { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /* 8 2.88MB 3.5" */
452*4882a593Smuzhiyun { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" }, /* 9 3.12MB 3.5" */
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */
455*4882a593Smuzhiyun { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */
456*4882a593Smuzhiyun { 820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410" }, /* 12 410KB 5.25" */
457*4882a593Smuzhiyun { 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820" }, /* 13 820KB 3.5" */
458*4882a593Smuzhiyun { 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" }, /* 14 1.48MB 5.25" */
459*4882a593Smuzhiyun { 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" }, /* 15 1.72MB 3.5" */
460*4882a593Smuzhiyun { 840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420" }, /* 16 420KB 5.25" */
461*4882a593Smuzhiyun { 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830" }, /* 17 830KB 3.5" */
462*4882a593Smuzhiyun { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" }, /* 18 1.49MB 5.25" */
463*4882a593Smuzhiyun { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5" */
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun { 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880" }, /* 20 880KB 5.25" */
466*4882a593Smuzhiyun { 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5" */
467*4882a593Smuzhiyun { 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5" */
468*4882a593Smuzhiyun { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25" */
469*4882a593Smuzhiyun { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5" */
470*4882a593Smuzhiyun { 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5" */
471*4882a593Smuzhiyun { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5" */
472*4882a593Smuzhiyun { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5" */
473*4882a593Smuzhiyun { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5" */
474*4882a593Smuzhiyun { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5" */
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */
477*4882a593Smuzhiyun { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */
478*4882a593Smuzhiyun };
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun #define SECTSIZE (_FD_SECTSIZE(*floppy))
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun /* Auto-detection: Disk type used until the next media change occurs. */
483*4882a593Smuzhiyun static struct floppy_struct *current_type[N_DRIVE];
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun /*
486*4882a593Smuzhiyun * User-provided type information. current_type points to
487*4882a593Smuzhiyun * the respective entry of this array.
488*4882a593Smuzhiyun */
489*4882a593Smuzhiyun static struct floppy_struct user_params[N_DRIVE];
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun static sector_t floppy_sizes[256];
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun static char floppy_device_name[] = "floppy";
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun /*
496*4882a593Smuzhiyun * The driver is trying to determine the correct media format
497*4882a593Smuzhiyun * while probing is set. rw_interrupt() clears it after a
498*4882a593Smuzhiyun * successful access.
499*4882a593Smuzhiyun */
500*4882a593Smuzhiyun static int probing;
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun /* Synchronization of FDC access. */
503*4882a593Smuzhiyun #define FD_COMMAND_NONE -1
504*4882a593Smuzhiyun #define FD_COMMAND_ERROR 2
505*4882a593Smuzhiyun #define FD_COMMAND_OKAY 3
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun static volatile int command_status = FD_COMMAND_NONE;
508*4882a593Smuzhiyun static unsigned long fdc_busy;
509*4882a593Smuzhiyun static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
510*4882a593Smuzhiyun static DECLARE_WAIT_QUEUE_HEAD(command_done);
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun /* errors encountered on the current (or last) request */
513*4882a593Smuzhiyun static int floppy_errors;
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun /* Format request descriptor. */
516*4882a593Smuzhiyun static struct format_descr format_req;
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun /*
519*4882a593Smuzhiyun * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps
520*4882a593Smuzhiyun * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc),
521*4882a593Smuzhiyun * H is head unload time (1=16ms, 2=32ms, etc)
522*4882a593Smuzhiyun */
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun /*
525*4882a593Smuzhiyun * Track buffer
526*4882a593Smuzhiyun * Because these are written to by the DMA controller, they must
527*4882a593Smuzhiyun * not contain a 64k byte boundary crossing, or data will be
528*4882a593Smuzhiyun * corrupted/lost.
529*4882a593Smuzhiyun */
530*4882a593Smuzhiyun static char *floppy_track_buffer;
531*4882a593Smuzhiyun static int max_buffer_sectors;
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun typedef void (*done_f)(int);
534*4882a593Smuzhiyun static const struct cont_t {
535*4882a593Smuzhiyun void (*interrupt)(void);
536*4882a593Smuzhiyun /* this is called after the interrupt of the
537*4882a593Smuzhiyun * main command */
538*4882a593Smuzhiyun void (*redo)(void); /* this is called to retry the operation */
539*4882a593Smuzhiyun void (*error)(void); /* this is called to tally an error */
540*4882a593Smuzhiyun done_f done; /* this is called to say if the operation has
541*4882a593Smuzhiyun * succeeded/failed */
542*4882a593Smuzhiyun } *cont;
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun static void floppy_ready(void);
545*4882a593Smuzhiyun static void floppy_start(void);
546*4882a593Smuzhiyun static void process_fd_request(void);
547*4882a593Smuzhiyun static void recalibrate_floppy(void);
548*4882a593Smuzhiyun static void floppy_shutdown(struct work_struct *);
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun static int floppy_request_regions(int);
551*4882a593Smuzhiyun static void floppy_release_regions(int);
552*4882a593Smuzhiyun static int floppy_grab_irq_and_dma(void);
553*4882a593Smuzhiyun static void floppy_release_irq_and_dma(void);
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun /*
556*4882a593Smuzhiyun * The "reset" variable should be tested whenever an interrupt is scheduled,
557*4882a593Smuzhiyun * after the commands have been sent. This is to ensure that the driver doesn't
558*4882a593Smuzhiyun * get wedged when the interrupt doesn't come because of a failed command.
559*4882a593Smuzhiyun * reset doesn't need to be tested before sending commands, because
560*4882a593Smuzhiyun * output_byte is automatically disabled when reset is set.
561*4882a593Smuzhiyun */
562*4882a593Smuzhiyun static void reset_fdc(void);
563*4882a593Smuzhiyun static int floppy_revalidate(struct gendisk *disk);
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun /*
566*4882a593Smuzhiyun * These are global variables, as that's the easiest way to give
567*4882a593Smuzhiyun * information to interrupts. They are the data used for the current
568*4882a593Smuzhiyun * request.
569*4882a593Smuzhiyun */
570*4882a593Smuzhiyun #define NO_TRACK -1
571*4882a593Smuzhiyun #define NEED_1_RECAL -2
572*4882a593Smuzhiyun #define NEED_2_RECAL -3
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun static atomic_t usage_count = ATOMIC_INIT(0);
575*4882a593Smuzhiyun
576*4882a593Smuzhiyun /* buffer related variables */
577*4882a593Smuzhiyun static int buffer_track = -1;
578*4882a593Smuzhiyun static int buffer_drive = -1;
579*4882a593Smuzhiyun static int buffer_min = -1;
580*4882a593Smuzhiyun static int buffer_max = -1;
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun /* fdc related variables, should end up in a struct */
583*4882a593Smuzhiyun static struct floppy_fdc_state fdc_state[N_FDC];
584*4882a593Smuzhiyun static int current_fdc; /* current fdc */
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun static struct workqueue_struct *floppy_wq;
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun static struct floppy_struct *_floppy = floppy_type;
589*4882a593Smuzhiyun static unsigned char current_drive;
590*4882a593Smuzhiyun static long current_count_sectors;
591*4882a593Smuzhiyun static unsigned char fsector_t; /* sector in track */
592*4882a593Smuzhiyun static unsigned char in_sector_offset; /* offset within physical sector,
593*4882a593Smuzhiyun * expressed in units of 512 bytes */
594*4882a593Smuzhiyun
fdc_inb(int fdc,int reg)595*4882a593Smuzhiyun static inline unsigned char fdc_inb(int fdc, int reg)
596*4882a593Smuzhiyun {
597*4882a593Smuzhiyun return fd_inb(fdc_state[fdc].address, reg);
598*4882a593Smuzhiyun }
599*4882a593Smuzhiyun
fdc_outb(unsigned char value,int fdc,int reg)600*4882a593Smuzhiyun static inline void fdc_outb(unsigned char value, int fdc, int reg)
601*4882a593Smuzhiyun {
602*4882a593Smuzhiyun fd_outb(value, fdc_state[fdc].address, reg);
603*4882a593Smuzhiyun }
604*4882a593Smuzhiyun
drive_no_geom(int drive)605*4882a593Smuzhiyun static inline bool drive_no_geom(int drive)
606*4882a593Smuzhiyun {
607*4882a593Smuzhiyun return !current_type[drive] && !ITYPE(drive_state[drive].fd_device);
608*4882a593Smuzhiyun }
609*4882a593Smuzhiyun
610*4882a593Smuzhiyun #ifndef fd_eject
fd_eject(int drive)611*4882a593Smuzhiyun static inline int fd_eject(int drive)
612*4882a593Smuzhiyun {
613*4882a593Smuzhiyun return -EINVAL;
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun #endif
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun /*
618*4882a593Smuzhiyun * Debugging
619*4882a593Smuzhiyun * =========
620*4882a593Smuzhiyun */
621*4882a593Smuzhiyun #ifdef DEBUGT
622*4882a593Smuzhiyun static long unsigned debugtimer;
623*4882a593Smuzhiyun
set_debugt(void)624*4882a593Smuzhiyun static inline void set_debugt(void)
625*4882a593Smuzhiyun {
626*4882a593Smuzhiyun debugtimer = jiffies;
627*4882a593Smuzhiyun }
628*4882a593Smuzhiyun
debugt(const char * func,const char * msg)629*4882a593Smuzhiyun static inline void debugt(const char *func, const char *msg)
630*4882a593Smuzhiyun {
631*4882a593Smuzhiyun if (drive_params[current_drive].flags & DEBUGT)
632*4882a593Smuzhiyun pr_info("%s:%s dtime=%lu\n", func, msg, jiffies - debugtimer);
633*4882a593Smuzhiyun }
634*4882a593Smuzhiyun #else
set_debugt(void)635*4882a593Smuzhiyun static inline void set_debugt(void) { }
debugt(const char * func,const char * msg)636*4882a593Smuzhiyun static inline void debugt(const char *func, const char *msg) { }
637*4882a593Smuzhiyun #endif /* DEBUGT */
638*4882a593Smuzhiyun
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun static DECLARE_DELAYED_WORK(fd_timeout, floppy_shutdown);
641*4882a593Smuzhiyun static const char *timeout_message;
642*4882a593Smuzhiyun
is_alive(const char * func,const char * message)643*4882a593Smuzhiyun static void is_alive(const char *func, const char *message)
644*4882a593Smuzhiyun {
645*4882a593Smuzhiyun /* this routine checks whether the floppy driver is "alive" */
646*4882a593Smuzhiyun if (test_bit(0, &fdc_busy) && command_status < 2 &&
647*4882a593Smuzhiyun !delayed_work_pending(&fd_timeout)) {
648*4882a593Smuzhiyun DPRINT("%s: timeout handler died. %s\n", func, message);
649*4882a593Smuzhiyun }
650*4882a593Smuzhiyun }
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun static void (*do_floppy)(void) = NULL;
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun #define OLOGSIZE 20
655*4882a593Smuzhiyun
656*4882a593Smuzhiyun static void (*lasthandler)(void);
657*4882a593Smuzhiyun static unsigned long interruptjiffies;
658*4882a593Smuzhiyun static unsigned long resultjiffies;
659*4882a593Smuzhiyun static int resultsize;
660*4882a593Smuzhiyun static unsigned long lastredo;
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun static struct output_log {
663*4882a593Smuzhiyun unsigned char data;
664*4882a593Smuzhiyun unsigned char status;
665*4882a593Smuzhiyun unsigned long jiffies;
666*4882a593Smuzhiyun } output_log[OLOGSIZE];
667*4882a593Smuzhiyun
668*4882a593Smuzhiyun static int output_log_pos;
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun #define MAXTIMEOUT -2
671*4882a593Smuzhiyun
__reschedule_timeout(int drive,const char * message)672*4882a593Smuzhiyun static void __reschedule_timeout(int drive, const char *message)
673*4882a593Smuzhiyun {
674*4882a593Smuzhiyun unsigned long delay;
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun if (drive < 0 || drive >= N_DRIVE) {
677*4882a593Smuzhiyun delay = 20UL * HZ;
678*4882a593Smuzhiyun drive = 0;
679*4882a593Smuzhiyun } else
680*4882a593Smuzhiyun delay = drive_params[drive].timeout;
681*4882a593Smuzhiyun
682*4882a593Smuzhiyun mod_delayed_work(floppy_wq, &fd_timeout, delay);
683*4882a593Smuzhiyun if (drive_params[drive].flags & FD_DEBUG)
684*4882a593Smuzhiyun DPRINT("reschedule timeout %s\n", message);
685*4882a593Smuzhiyun timeout_message = message;
686*4882a593Smuzhiyun }
687*4882a593Smuzhiyun
reschedule_timeout(int drive,const char * message)688*4882a593Smuzhiyun static void reschedule_timeout(int drive, const char *message)
689*4882a593Smuzhiyun {
690*4882a593Smuzhiyun unsigned long flags;
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun spin_lock_irqsave(&floppy_lock, flags);
693*4882a593Smuzhiyun __reschedule_timeout(drive, message);
694*4882a593Smuzhiyun spin_unlock_irqrestore(&floppy_lock, flags);
695*4882a593Smuzhiyun }
696*4882a593Smuzhiyun
697*4882a593Smuzhiyun #define INFBOUND(a, b) (a) = max_t(int, a, b)
698*4882a593Smuzhiyun #define SUPBOUND(a, b) (a) = min_t(int, a, b)
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun /*
701*4882a593Smuzhiyun * Bottom half floppy driver.
702*4882a593Smuzhiyun * ==========================
703*4882a593Smuzhiyun *
704*4882a593Smuzhiyun * This part of the file contains the code talking directly to the hardware,
705*4882a593Smuzhiyun * and also the main service loop (seek-configure-spinup-command)
706*4882a593Smuzhiyun */
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun /*
709*4882a593Smuzhiyun * disk change.
710*4882a593Smuzhiyun * This routine is responsible for maintaining the FD_DISK_CHANGE flag,
711*4882a593Smuzhiyun * and the last_checked date.
712*4882a593Smuzhiyun *
713*4882a593Smuzhiyun * last_checked is the date of the last check which showed 'no disk change'
714*4882a593Smuzhiyun * FD_DISK_CHANGE is set under two conditions:
715*4882a593Smuzhiyun * 1. The floppy has been changed after some i/o to that floppy already
716*4882a593Smuzhiyun * took place.
717*4882a593Smuzhiyun * 2. No floppy disk is in the drive. This is done in order to ensure that
718*4882a593Smuzhiyun * requests are quickly flushed in case there is no disk in the drive. It
719*4882a593Smuzhiyun * follows that FD_DISK_CHANGE can only be cleared if there is a disk in
720*4882a593Smuzhiyun * the drive.
721*4882a593Smuzhiyun *
722*4882a593Smuzhiyun * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet.
723*4882a593Smuzhiyun * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on
724*4882a593Smuzhiyun * each seek. If a disk is present, the disk change line should also be
725*4882a593Smuzhiyun * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk
726*4882a593Smuzhiyun * change line is set, this means either that no disk is in the drive, or
727*4882a593Smuzhiyun * that it has been removed since the last seek.
728*4882a593Smuzhiyun *
729*4882a593Smuzhiyun * This means that we really have a third possibility too:
730*4882a593Smuzhiyun * The floppy has been changed after the last seek.
731*4882a593Smuzhiyun */
732*4882a593Smuzhiyun
disk_change(int drive)733*4882a593Smuzhiyun static int disk_change(int drive)
734*4882a593Smuzhiyun {
735*4882a593Smuzhiyun int fdc = FDC(drive);
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun if (time_before(jiffies, drive_state[drive].select_date + drive_params[drive].select_delay))
738*4882a593Smuzhiyun DPRINT("WARNING disk change called early\n");
739*4882a593Smuzhiyun if (!(fdc_state[fdc].dor & (0x10 << UNIT(drive))) ||
740*4882a593Smuzhiyun (fdc_state[fdc].dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
741*4882a593Smuzhiyun DPRINT("probing disk change on unselected drive\n");
742*4882a593Smuzhiyun DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
743*4882a593Smuzhiyun (unsigned int)fdc_state[fdc].dor);
744*4882a593Smuzhiyun }
745*4882a593Smuzhiyun
746*4882a593Smuzhiyun debug_dcl(drive_params[drive].flags,
747*4882a593Smuzhiyun "checking disk change line for drive %d\n", drive);
748*4882a593Smuzhiyun debug_dcl(drive_params[drive].flags, "jiffies=%lu\n", jiffies);
749*4882a593Smuzhiyun debug_dcl(drive_params[drive].flags, "disk change line=%x\n",
750*4882a593Smuzhiyun fdc_inb(fdc, FD_DIR) & 0x80);
751*4882a593Smuzhiyun debug_dcl(drive_params[drive].flags, "flags=%lx\n",
752*4882a593Smuzhiyun drive_state[drive].flags);
753*4882a593Smuzhiyun
754*4882a593Smuzhiyun if (drive_params[drive].flags & FD_BROKEN_DCL)
755*4882a593Smuzhiyun return test_bit(FD_DISK_CHANGED_BIT,
756*4882a593Smuzhiyun &drive_state[drive].flags);
757*4882a593Smuzhiyun if ((fdc_inb(fdc, FD_DIR) ^ drive_params[drive].flags) & 0x80) {
758*4882a593Smuzhiyun set_bit(FD_VERIFY_BIT, &drive_state[drive].flags);
759*4882a593Smuzhiyun /* verify write protection */
760*4882a593Smuzhiyun
761*4882a593Smuzhiyun if (drive_state[drive].maxblock) /* mark it changed */
762*4882a593Smuzhiyun set_bit(FD_DISK_CHANGED_BIT,
763*4882a593Smuzhiyun &drive_state[drive].flags);
764*4882a593Smuzhiyun
765*4882a593Smuzhiyun /* invalidate its geometry */
766*4882a593Smuzhiyun if (drive_state[drive].keep_data >= 0) {
767*4882a593Smuzhiyun if ((drive_params[drive].flags & FTD_MSG) &&
768*4882a593Smuzhiyun current_type[drive] != NULL)
769*4882a593Smuzhiyun DPRINT("Disk type is undefined after disk change\n");
770*4882a593Smuzhiyun current_type[drive] = NULL;
771*4882a593Smuzhiyun floppy_sizes[TOMINOR(drive)] = MAX_DISK_SIZE << 1;
772*4882a593Smuzhiyun }
773*4882a593Smuzhiyun
774*4882a593Smuzhiyun return 1;
775*4882a593Smuzhiyun } else {
776*4882a593Smuzhiyun drive_state[drive].last_checked = jiffies;
777*4882a593Smuzhiyun clear_bit(FD_DISK_NEWCHANGE_BIT, &drive_state[drive].flags);
778*4882a593Smuzhiyun }
779*4882a593Smuzhiyun return 0;
780*4882a593Smuzhiyun }
781*4882a593Smuzhiyun
is_selected(int dor,int unit)782*4882a593Smuzhiyun static inline int is_selected(int dor, int unit)
783*4882a593Smuzhiyun {
784*4882a593Smuzhiyun return ((dor & (0x10 << unit)) && (dor & 3) == unit);
785*4882a593Smuzhiyun }
786*4882a593Smuzhiyun
is_ready_state(int status)787*4882a593Smuzhiyun static bool is_ready_state(int status)
788*4882a593Smuzhiyun {
789*4882a593Smuzhiyun int state = status & (STATUS_READY | STATUS_DIR | STATUS_DMA);
790*4882a593Smuzhiyun return state == STATUS_READY;
791*4882a593Smuzhiyun }
792*4882a593Smuzhiyun
set_dor(int fdc,char mask,char data)793*4882a593Smuzhiyun static int set_dor(int fdc, char mask, char data)
794*4882a593Smuzhiyun {
795*4882a593Smuzhiyun unsigned char unit;
796*4882a593Smuzhiyun unsigned char drive;
797*4882a593Smuzhiyun unsigned char newdor;
798*4882a593Smuzhiyun unsigned char olddor;
799*4882a593Smuzhiyun
800*4882a593Smuzhiyun if (fdc_state[fdc].address == -1)
801*4882a593Smuzhiyun return -1;
802*4882a593Smuzhiyun
803*4882a593Smuzhiyun olddor = fdc_state[fdc].dor;
804*4882a593Smuzhiyun newdor = (olddor & mask) | data;
805*4882a593Smuzhiyun if (newdor != olddor) {
806*4882a593Smuzhiyun unit = olddor & 0x3;
807*4882a593Smuzhiyun if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
808*4882a593Smuzhiyun drive = REVDRIVE(fdc, unit);
809*4882a593Smuzhiyun debug_dcl(drive_params[drive].flags,
810*4882a593Smuzhiyun "calling disk change from set_dor\n");
811*4882a593Smuzhiyun disk_change(drive);
812*4882a593Smuzhiyun }
813*4882a593Smuzhiyun fdc_state[fdc].dor = newdor;
814*4882a593Smuzhiyun fdc_outb(newdor, fdc, FD_DOR);
815*4882a593Smuzhiyun
816*4882a593Smuzhiyun unit = newdor & 0x3;
817*4882a593Smuzhiyun if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
818*4882a593Smuzhiyun drive = REVDRIVE(fdc, unit);
819*4882a593Smuzhiyun drive_state[drive].select_date = jiffies;
820*4882a593Smuzhiyun }
821*4882a593Smuzhiyun }
822*4882a593Smuzhiyun return olddor;
823*4882a593Smuzhiyun }
824*4882a593Smuzhiyun
twaddle(int fdc,int drive)825*4882a593Smuzhiyun static void twaddle(int fdc, int drive)
826*4882a593Smuzhiyun {
827*4882a593Smuzhiyun if (drive_params[drive].select_delay)
828*4882a593Smuzhiyun return;
829*4882a593Smuzhiyun fdc_outb(fdc_state[fdc].dor & ~(0x10 << UNIT(drive)),
830*4882a593Smuzhiyun fdc, FD_DOR);
831*4882a593Smuzhiyun fdc_outb(fdc_state[fdc].dor, fdc, FD_DOR);
832*4882a593Smuzhiyun drive_state[drive].select_date = jiffies;
833*4882a593Smuzhiyun }
834*4882a593Smuzhiyun
835*4882a593Smuzhiyun /*
836*4882a593Smuzhiyun * Reset all driver information about the specified fdc.
837*4882a593Smuzhiyun * This is needed after a reset, and after a raw command.
838*4882a593Smuzhiyun */
reset_fdc_info(int fdc,int mode)839*4882a593Smuzhiyun static void reset_fdc_info(int fdc, int mode)
840*4882a593Smuzhiyun {
841*4882a593Smuzhiyun int drive;
842*4882a593Smuzhiyun
843*4882a593Smuzhiyun fdc_state[fdc].spec1 = fdc_state[fdc].spec2 = -1;
844*4882a593Smuzhiyun fdc_state[fdc].need_configure = 1;
845*4882a593Smuzhiyun fdc_state[fdc].perp_mode = 1;
846*4882a593Smuzhiyun fdc_state[fdc].rawcmd = 0;
847*4882a593Smuzhiyun for (drive = 0; drive < N_DRIVE; drive++)
848*4882a593Smuzhiyun if (FDC(drive) == fdc &&
849*4882a593Smuzhiyun (mode || drive_state[drive].track != NEED_1_RECAL))
850*4882a593Smuzhiyun drive_state[drive].track = NEED_2_RECAL;
851*4882a593Smuzhiyun }
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun /*
854*4882a593Smuzhiyun * selects the fdc and drive, and enables the fdc's input/dma.
855*4882a593Smuzhiyun * Both current_drive and current_fdc are changed to match the new drive.
856*4882a593Smuzhiyun */
set_fdc(int drive)857*4882a593Smuzhiyun static void set_fdc(int drive)
858*4882a593Smuzhiyun {
859*4882a593Smuzhiyun unsigned int fdc;
860*4882a593Smuzhiyun
861*4882a593Smuzhiyun if (drive < 0 || drive >= N_DRIVE) {
862*4882a593Smuzhiyun pr_info("bad drive value %d\n", drive);
863*4882a593Smuzhiyun return;
864*4882a593Smuzhiyun }
865*4882a593Smuzhiyun
866*4882a593Smuzhiyun fdc = FDC(drive);
867*4882a593Smuzhiyun if (fdc >= N_FDC) {
868*4882a593Smuzhiyun pr_info("bad fdc value\n");
869*4882a593Smuzhiyun return;
870*4882a593Smuzhiyun }
871*4882a593Smuzhiyun
872*4882a593Smuzhiyun set_dor(fdc, ~0, 8);
873*4882a593Smuzhiyun #if N_FDC > 1
874*4882a593Smuzhiyun set_dor(1 - fdc, ~8, 0);
875*4882a593Smuzhiyun #endif
876*4882a593Smuzhiyun if (fdc_state[fdc].rawcmd == 2)
877*4882a593Smuzhiyun reset_fdc_info(fdc, 1);
878*4882a593Smuzhiyun if (fdc_inb(fdc, FD_STATUS) != STATUS_READY)
879*4882a593Smuzhiyun fdc_state[fdc].reset = 1;
880*4882a593Smuzhiyun
881*4882a593Smuzhiyun current_drive = drive;
882*4882a593Smuzhiyun current_fdc = fdc;
883*4882a593Smuzhiyun }
884*4882a593Smuzhiyun
885*4882a593Smuzhiyun /*
886*4882a593Smuzhiyun * locks the driver.
887*4882a593Smuzhiyun * Both current_drive and current_fdc are changed to match the new drive.
888*4882a593Smuzhiyun */
lock_fdc(int drive)889*4882a593Smuzhiyun static int lock_fdc(int drive)
890*4882a593Smuzhiyun {
891*4882a593Smuzhiyun if (WARN(atomic_read(&usage_count) == 0,
892*4882a593Smuzhiyun "Trying to lock fdc while usage count=0\n"))
893*4882a593Smuzhiyun return -1;
894*4882a593Smuzhiyun
895*4882a593Smuzhiyun if (wait_event_interruptible(fdc_wait, !test_and_set_bit(0, &fdc_busy)))
896*4882a593Smuzhiyun return -EINTR;
897*4882a593Smuzhiyun
898*4882a593Smuzhiyun command_status = FD_COMMAND_NONE;
899*4882a593Smuzhiyun
900*4882a593Smuzhiyun reschedule_timeout(drive, "lock fdc");
901*4882a593Smuzhiyun set_fdc(drive);
902*4882a593Smuzhiyun return 0;
903*4882a593Smuzhiyun }
904*4882a593Smuzhiyun
905*4882a593Smuzhiyun /* unlocks the driver */
unlock_fdc(void)906*4882a593Smuzhiyun static void unlock_fdc(void)
907*4882a593Smuzhiyun {
908*4882a593Smuzhiyun if (!test_bit(0, &fdc_busy))
909*4882a593Smuzhiyun DPRINT("FDC access conflict!\n");
910*4882a593Smuzhiyun
911*4882a593Smuzhiyun raw_cmd = NULL;
912*4882a593Smuzhiyun command_status = FD_COMMAND_NONE;
913*4882a593Smuzhiyun cancel_delayed_work(&fd_timeout);
914*4882a593Smuzhiyun do_floppy = NULL;
915*4882a593Smuzhiyun cont = NULL;
916*4882a593Smuzhiyun clear_bit(0, &fdc_busy);
917*4882a593Smuzhiyun wake_up(&fdc_wait);
918*4882a593Smuzhiyun }
919*4882a593Smuzhiyun
920*4882a593Smuzhiyun /* switches the motor off after a given timeout */
motor_off_callback(struct timer_list * t)921*4882a593Smuzhiyun static void motor_off_callback(struct timer_list *t)
922*4882a593Smuzhiyun {
923*4882a593Smuzhiyun unsigned long nr = t - motor_off_timer;
924*4882a593Smuzhiyun unsigned char mask = ~(0x10 << UNIT(nr));
925*4882a593Smuzhiyun
926*4882a593Smuzhiyun if (WARN_ON_ONCE(nr >= N_DRIVE))
927*4882a593Smuzhiyun return;
928*4882a593Smuzhiyun
929*4882a593Smuzhiyun set_dor(FDC(nr), mask, 0);
930*4882a593Smuzhiyun }
931*4882a593Smuzhiyun
932*4882a593Smuzhiyun /* schedules motor off */
floppy_off(unsigned int drive)933*4882a593Smuzhiyun static void floppy_off(unsigned int drive)
934*4882a593Smuzhiyun {
935*4882a593Smuzhiyun unsigned long volatile delta;
936*4882a593Smuzhiyun int fdc = FDC(drive);
937*4882a593Smuzhiyun
938*4882a593Smuzhiyun if (!(fdc_state[fdc].dor & (0x10 << UNIT(drive))))
939*4882a593Smuzhiyun return;
940*4882a593Smuzhiyun
941*4882a593Smuzhiyun del_timer(motor_off_timer + drive);
942*4882a593Smuzhiyun
943*4882a593Smuzhiyun /* make spindle stop in a position which minimizes spinup time
944*4882a593Smuzhiyun * next time */
945*4882a593Smuzhiyun if (drive_params[drive].rps) {
946*4882a593Smuzhiyun delta = jiffies - drive_state[drive].first_read_date + HZ -
947*4882a593Smuzhiyun drive_params[drive].spindown_offset;
948*4882a593Smuzhiyun delta = ((delta * drive_params[drive].rps) % HZ) / drive_params[drive].rps;
949*4882a593Smuzhiyun motor_off_timer[drive].expires =
950*4882a593Smuzhiyun jiffies + drive_params[drive].spindown - delta;
951*4882a593Smuzhiyun }
952*4882a593Smuzhiyun add_timer(motor_off_timer + drive);
953*4882a593Smuzhiyun }
954*4882a593Smuzhiyun
955*4882a593Smuzhiyun /*
956*4882a593Smuzhiyun * cycle through all N_DRIVE floppy drives, for disk change testing.
957*4882a593Smuzhiyun * stopping at current drive. This is done before any long operation, to
958*4882a593Smuzhiyun * be sure to have up to date disk change information.
959*4882a593Smuzhiyun */
scandrives(void)960*4882a593Smuzhiyun static void scandrives(void)
961*4882a593Smuzhiyun {
962*4882a593Smuzhiyun int i;
963*4882a593Smuzhiyun int drive;
964*4882a593Smuzhiyun int saved_drive;
965*4882a593Smuzhiyun
966*4882a593Smuzhiyun if (drive_params[current_drive].select_delay)
967*4882a593Smuzhiyun return;
968*4882a593Smuzhiyun
969*4882a593Smuzhiyun saved_drive = current_drive;
970*4882a593Smuzhiyun for (i = 0; i < N_DRIVE; i++) {
971*4882a593Smuzhiyun drive = (saved_drive + i + 1) % N_DRIVE;
972*4882a593Smuzhiyun if (drive_state[drive].fd_ref == 0 || drive_params[drive].select_delay != 0)
973*4882a593Smuzhiyun continue; /* skip closed drives */
974*4882a593Smuzhiyun set_fdc(drive);
975*4882a593Smuzhiyun if (!(set_dor(current_fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
976*4882a593Smuzhiyun (0x10 << UNIT(drive))))
977*4882a593Smuzhiyun /* switch the motor off again, if it was off to
978*4882a593Smuzhiyun * begin with */
979*4882a593Smuzhiyun set_dor(current_fdc, ~(0x10 << UNIT(drive)), 0);
980*4882a593Smuzhiyun }
981*4882a593Smuzhiyun set_fdc(saved_drive);
982*4882a593Smuzhiyun }
983*4882a593Smuzhiyun
empty(void)984*4882a593Smuzhiyun static void empty(void)
985*4882a593Smuzhiyun {
986*4882a593Smuzhiyun }
987*4882a593Smuzhiyun
988*4882a593Smuzhiyun static void (*floppy_work_fn)(void);
989*4882a593Smuzhiyun
floppy_work_workfn(struct work_struct * work)990*4882a593Smuzhiyun static void floppy_work_workfn(struct work_struct *work)
991*4882a593Smuzhiyun {
992*4882a593Smuzhiyun floppy_work_fn();
993*4882a593Smuzhiyun }
994*4882a593Smuzhiyun
995*4882a593Smuzhiyun static DECLARE_WORK(floppy_work, floppy_work_workfn);
996*4882a593Smuzhiyun
schedule_bh(void (* handler)(void))997*4882a593Smuzhiyun static void schedule_bh(void (*handler)(void))
998*4882a593Smuzhiyun {
999*4882a593Smuzhiyun WARN_ON(work_pending(&floppy_work));
1000*4882a593Smuzhiyun
1001*4882a593Smuzhiyun floppy_work_fn = handler;
1002*4882a593Smuzhiyun queue_work(floppy_wq, &floppy_work);
1003*4882a593Smuzhiyun }
1004*4882a593Smuzhiyun
1005*4882a593Smuzhiyun static void (*fd_timer_fn)(void) = NULL;
1006*4882a593Smuzhiyun
fd_timer_workfn(struct work_struct * work)1007*4882a593Smuzhiyun static void fd_timer_workfn(struct work_struct *work)
1008*4882a593Smuzhiyun {
1009*4882a593Smuzhiyun fd_timer_fn();
1010*4882a593Smuzhiyun }
1011*4882a593Smuzhiyun
1012*4882a593Smuzhiyun static DECLARE_DELAYED_WORK(fd_timer, fd_timer_workfn);
1013*4882a593Smuzhiyun
cancel_activity(void)1014*4882a593Smuzhiyun static void cancel_activity(void)
1015*4882a593Smuzhiyun {
1016*4882a593Smuzhiyun do_floppy = NULL;
1017*4882a593Smuzhiyun cancel_delayed_work(&fd_timer);
1018*4882a593Smuzhiyun cancel_work_sync(&floppy_work);
1019*4882a593Smuzhiyun }
1020*4882a593Smuzhiyun
1021*4882a593Smuzhiyun /* this function makes sure that the disk stays in the drive during the
1022*4882a593Smuzhiyun * transfer */
fd_watchdog(void)1023*4882a593Smuzhiyun static void fd_watchdog(void)
1024*4882a593Smuzhiyun {
1025*4882a593Smuzhiyun debug_dcl(drive_params[current_drive].flags,
1026*4882a593Smuzhiyun "calling disk change from watchdog\n");
1027*4882a593Smuzhiyun
1028*4882a593Smuzhiyun if (disk_change(current_drive)) {
1029*4882a593Smuzhiyun DPRINT("disk removed during i/o\n");
1030*4882a593Smuzhiyun cancel_activity();
1031*4882a593Smuzhiyun cont->done(0);
1032*4882a593Smuzhiyun reset_fdc();
1033*4882a593Smuzhiyun } else {
1034*4882a593Smuzhiyun cancel_delayed_work(&fd_timer);
1035*4882a593Smuzhiyun fd_timer_fn = fd_watchdog;
1036*4882a593Smuzhiyun queue_delayed_work(floppy_wq, &fd_timer, HZ / 10);
1037*4882a593Smuzhiyun }
1038*4882a593Smuzhiyun }
1039*4882a593Smuzhiyun
main_command_interrupt(void)1040*4882a593Smuzhiyun static void main_command_interrupt(void)
1041*4882a593Smuzhiyun {
1042*4882a593Smuzhiyun cancel_delayed_work(&fd_timer);
1043*4882a593Smuzhiyun cont->interrupt();
1044*4882a593Smuzhiyun }
1045*4882a593Smuzhiyun
1046*4882a593Smuzhiyun /* waits for a delay (spinup or select) to pass */
fd_wait_for_completion(unsigned long expires,void (* function)(void))1047*4882a593Smuzhiyun static int fd_wait_for_completion(unsigned long expires,
1048*4882a593Smuzhiyun void (*function)(void))
1049*4882a593Smuzhiyun {
1050*4882a593Smuzhiyun if (fdc_state[current_fdc].reset) {
1051*4882a593Smuzhiyun reset_fdc(); /* do the reset during sleep to win time
1052*4882a593Smuzhiyun * if we don't need to sleep, it's a good
1053*4882a593Smuzhiyun * occasion anyways */
1054*4882a593Smuzhiyun return 1;
1055*4882a593Smuzhiyun }
1056*4882a593Smuzhiyun
1057*4882a593Smuzhiyun if (time_before(jiffies, expires)) {
1058*4882a593Smuzhiyun cancel_delayed_work(&fd_timer);
1059*4882a593Smuzhiyun fd_timer_fn = function;
1060*4882a593Smuzhiyun queue_delayed_work(floppy_wq, &fd_timer, expires - jiffies);
1061*4882a593Smuzhiyun return 1;
1062*4882a593Smuzhiyun }
1063*4882a593Smuzhiyun return 0;
1064*4882a593Smuzhiyun }
1065*4882a593Smuzhiyun
setup_DMA(void)1066*4882a593Smuzhiyun static void setup_DMA(void)
1067*4882a593Smuzhiyun {
1068*4882a593Smuzhiyun unsigned long f;
1069*4882a593Smuzhiyun
1070*4882a593Smuzhiyun if (raw_cmd->length == 0) {
1071*4882a593Smuzhiyun print_hex_dump(KERN_INFO, "zero dma transfer size: ",
1072*4882a593Smuzhiyun DUMP_PREFIX_NONE, 16, 1,
1073*4882a593Smuzhiyun raw_cmd->fullcmd, raw_cmd->cmd_count, false);
1074*4882a593Smuzhiyun cont->done(0);
1075*4882a593Smuzhiyun fdc_state[current_fdc].reset = 1;
1076*4882a593Smuzhiyun return;
1077*4882a593Smuzhiyun }
1078*4882a593Smuzhiyun if (((unsigned long)raw_cmd->kernel_data) % 512) {
1079*4882a593Smuzhiyun pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
1080*4882a593Smuzhiyun cont->done(0);
1081*4882a593Smuzhiyun fdc_state[current_fdc].reset = 1;
1082*4882a593Smuzhiyun return;
1083*4882a593Smuzhiyun }
1084*4882a593Smuzhiyun f = claim_dma_lock();
1085*4882a593Smuzhiyun fd_disable_dma();
1086*4882a593Smuzhiyun #ifdef fd_dma_setup
1087*4882a593Smuzhiyun if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
1088*4882a593Smuzhiyun (raw_cmd->flags & FD_RAW_READ) ?
1089*4882a593Smuzhiyun DMA_MODE_READ : DMA_MODE_WRITE,
1090*4882a593Smuzhiyun fdc_state[current_fdc].address) < 0) {
1091*4882a593Smuzhiyun release_dma_lock(f);
1092*4882a593Smuzhiyun cont->done(0);
1093*4882a593Smuzhiyun fdc_state[current_fdc].reset = 1;
1094*4882a593Smuzhiyun return;
1095*4882a593Smuzhiyun }
1096*4882a593Smuzhiyun release_dma_lock(f);
1097*4882a593Smuzhiyun #else
1098*4882a593Smuzhiyun fd_clear_dma_ff();
1099*4882a593Smuzhiyun fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length);
1100*4882a593Smuzhiyun fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ) ?
1101*4882a593Smuzhiyun DMA_MODE_READ : DMA_MODE_WRITE);
1102*4882a593Smuzhiyun fd_set_dma_addr(raw_cmd->kernel_data);
1103*4882a593Smuzhiyun fd_set_dma_count(raw_cmd->length);
1104*4882a593Smuzhiyun virtual_dma_port = fdc_state[current_fdc].address;
1105*4882a593Smuzhiyun fd_enable_dma();
1106*4882a593Smuzhiyun release_dma_lock(f);
1107*4882a593Smuzhiyun #endif
1108*4882a593Smuzhiyun }
1109*4882a593Smuzhiyun
1110*4882a593Smuzhiyun static void show_floppy(int fdc);
1111*4882a593Smuzhiyun
1112*4882a593Smuzhiyun /* waits until the fdc becomes ready */
wait_til_ready(int fdc)1113*4882a593Smuzhiyun static int wait_til_ready(int fdc)
1114*4882a593Smuzhiyun {
1115*4882a593Smuzhiyun int status;
1116*4882a593Smuzhiyun int counter;
1117*4882a593Smuzhiyun
1118*4882a593Smuzhiyun if (fdc_state[fdc].reset)
1119*4882a593Smuzhiyun return -1;
1120*4882a593Smuzhiyun for (counter = 0; counter < 10000; counter++) {
1121*4882a593Smuzhiyun status = fdc_inb(fdc, FD_STATUS);
1122*4882a593Smuzhiyun if (status & STATUS_READY)
1123*4882a593Smuzhiyun return status;
1124*4882a593Smuzhiyun }
1125*4882a593Smuzhiyun if (initialized) {
1126*4882a593Smuzhiyun DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
1127*4882a593Smuzhiyun show_floppy(fdc);
1128*4882a593Smuzhiyun }
1129*4882a593Smuzhiyun fdc_state[fdc].reset = 1;
1130*4882a593Smuzhiyun return -1;
1131*4882a593Smuzhiyun }
1132*4882a593Smuzhiyun
1133*4882a593Smuzhiyun /* sends a command byte to the fdc */
output_byte(int fdc,char byte)1134*4882a593Smuzhiyun static int output_byte(int fdc, char byte)
1135*4882a593Smuzhiyun {
1136*4882a593Smuzhiyun int status = wait_til_ready(fdc);
1137*4882a593Smuzhiyun
1138*4882a593Smuzhiyun if (status < 0)
1139*4882a593Smuzhiyun return -1;
1140*4882a593Smuzhiyun
1141*4882a593Smuzhiyun if (is_ready_state(status)) {
1142*4882a593Smuzhiyun fdc_outb(byte, fdc, FD_DATA);
1143*4882a593Smuzhiyun output_log[output_log_pos].data = byte;
1144*4882a593Smuzhiyun output_log[output_log_pos].status = status;
1145*4882a593Smuzhiyun output_log[output_log_pos].jiffies = jiffies;
1146*4882a593Smuzhiyun output_log_pos = (output_log_pos + 1) % OLOGSIZE;
1147*4882a593Smuzhiyun return 0;
1148*4882a593Smuzhiyun }
1149*4882a593Smuzhiyun fdc_state[fdc].reset = 1;
1150*4882a593Smuzhiyun if (initialized) {
1151*4882a593Smuzhiyun DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
1152*4882a593Smuzhiyun byte, fdc, status);
1153*4882a593Smuzhiyun show_floppy(fdc);
1154*4882a593Smuzhiyun }
1155*4882a593Smuzhiyun return -1;
1156*4882a593Smuzhiyun }
1157*4882a593Smuzhiyun
1158*4882a593Smuzhiyun /* gets the response from the fdc */
result(int fdc)1159*4882a593Smuzhiyun static int result(int fdc)
1160*4882a593Smuzhiyun {
1161*4882a593Smuzhiyun int i;
1162*4882a593Smuzhiyun int status = 0;
1163*4882a593Smuzhiyun
1164*4882a593Smuzhiyun for (i = 0; i < FD_RAW_REPLY_SIZE; i++) {
1165*4882a593Smuzhiyun status = wait_til_ready(fdc);
1166*4882a593Smuzhiyun if (status < 0)
1167*4882a593Smuzhiyun break;
1168*4882a593Smuzhiyun status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
1169*4882a593Smuzhiyun if ((status & ~STATUS_BUSY) == STATUS_READY) {
1170*4882a593Smuzhiyun resultjiffies = jiffies;
1171*4882a593Smuzhiyun resultsize = i;
1172*4882a593Smuzhiyun return i;
1173*4882a593Smuzhiyun }
1174*4882a593Smuzhiyun if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
1175*4882a593Smuzhiyun reply_buffer[i] = fdc_inb(fdc, FD_DATA);
1176*4882a593Smuzhiyun else
1177*4882a593Smuzhiyun break;
1178*4882a593Smuzhiyun }
1179*4882a593Smuzhiyun if (initialized) {
1180*4882a593Smuzhiyun DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
1181*4882a593Smuzhiyun fdc, status, i);
1182*4882a593Smuzhiyun show_floppy(fdc);
1183*4882a593Smuzhiyun }
1184*4882a593Smuzhiyun fdc_state[fdc].reset = 1;
1185*4882a593Smuzhiyun return -1;
1186*4882a593Smuzhiyun }
1187*4882a593Smuzhiyun
1188*4882a593Smuzhiyun #define MORE_OUTPUT -2
1189*4882a593Smuzhiyun /* does the fdc need more output? */
need_more_output(int fdc)1190*4882a593Smuzhiyun static int need_more_output(int fdc)
1191*4882a593Smuzhiyun {
1192*4882a593Smuzhiyun int status = wait_til_ready(fdc);
1193*4882a593Smuzhiyun
1194*4882a593Smuzhiyun if (status < 0)
1195*4882a593Smuzhiyun return -1;
1196*4882a593Smuzhiyun
1197*4882a593Smuzhiyun if (is_ready_state(status))
1198*4882a593Smuzhiyun return MORE_OUTPUT;
1199*4882a593Smuzhiyun
1200*4882a593Smuzhiyun return result(fdc);
1201*4882a593Smuzhiyun }
1202*4882a593Smuzhiyun
1203*4882a593Smuzhiyun /* Set perpendicular mode as required, based on data rate, if supported.
1204*4882a593Smuzhiyun * 82077 Now tested. 1Mbps data rate only possible with 82077-1.
1205*4882a593Smuzhiyun */
perpendicular_mode(int fdc)1206*4882a593Smuzhiyun static void perpendicular_mode(int fdc)
1207*4882a593Smuzhiyun {
1208*4882a593Smuzhiyun unsigned char perp_mode;
1209*4882a593Smuzhiyun
1210*4882a593Smuzhiyun if (raw_cmd->rate & 0x40) {
1211*4882a593Smuzhiyun switch (raw_cmd->rate & 3) {
1212*4882a593Smuzhiyun case 0:
1213*4882a593Smuzhiyun perp_mode = 2;
1214*4882a593Smuzhiyun break;
1215*4882a593Smuzhiyun case 3:
1216*4882a593Smuzhiyun perp_mode = 3;
1217*4882a593Smuzhiyun break;
1218*4882a593Smuzhiyun default:
1219*4882a593Smuzhiyun DPRINT("Invalid data rate for perpendicular mode!\n");
1220*4882a593Smuzhiyun cont->done(0);
1221*4882a593Smuzhiyun fdc_state[fdc].reset = 1;
1222*4882a593Smuzhiyun /*
1223*4882a593Smuzhiyun * convenient way to return to
1224*4882a593Smuzhiyun * redo without too much hassle
1225*4882a593Smuzhiyun * (deep stack et al.)
1226*4882a593Smuzhiyun */
1227*4882a593Smuzhiyun return;
1228*4882a593Smuzhiyun }
1229*4882a593Smuzhiyun } else
1230*4882a593Smuzhiyun perp_mode = 0;
1231*4882a593Smuzhiyun
1232*4882a593Smuzhiyun if (fdc_state[fdc].perp_mode == perp_mode)
1233*4882a593Smuzhiyun return;
1234*4882a593Smuzhiyun if (fdc_state[fdc].version >= FDC_82077_ORIG) {
1235*4882a593Smuzhiyun output_byte(fdc, FD_PERPENDICULAR);
1236*4882a593Smuzhiyun output_byte(fdc, perp_mode);
1237*4882a593Smuzhiyun fdc_state[fdc].perp_mode = perp_mode;
1238*4882a593Smuzhiyun } else if (perp_mode) {
1239*4882a593Smuzhiyun DPRINT("perpendicular mode not supported by this FDC.\n");
1240*4882a593Smuzhiyun }
1241*4882a593Smuzhiyun } /* perpendicular_mode */
1242*4882a593Smuzhiyun
1243*4882a593Smuzhiyun static int fifo_depth = 0xa;
1244*4882a593Smuzhiyun static int no_fifo;
1245*4882a593Smuzhiyun
fdc_configure(int fdc)1246*4882a593Smuzhiyun static int fdc_configure(int fdc)
1247*4882a593Smuzhiyun {
1248*4882a593Smuzhiyun /* Turn on FIFO */
1249*4882a593Smuzhiyun output_byte(fdc, FD_CONFIGURE);
1250*4882a593Smuzhiyun if (need_more_output(fdc) != MORE_OUTPUT)
1251*4882a593Smuzhiyun return 0;
1252*4882a593Smuzhiyun output_byte(fdc, 0);
1253*4882a593Smuzhiyun output_byte(fdc, 0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
1254*4882a593Smuzhiyun output_byte(fdc, 0); /* pre-compensation from track 0 upwards */
1255*4882a593Smuzhiyun return 1;
1256*4882a593Smuzhiyun }
1257*4882a593Smuzhiyun
1258*4882a593Smuzhiyun #define NOMINAL_DTR 500
1259*4882a593Smuzhiyun
1260*4882a593Smuzhiyun /* Issue a "SPECIFY" command to set the step rate time, head unload time,
1261*4882a593Smuzhiyun * head load time, and DMA disable flag to values needed by floppy.
1262*4882a593Smuzhiyun *
1263*4882a593Smuzhiyun * The value "dtr" is the data transfer rate in Kbps. It is needed
1264*4882a593Smuzhiyun * to account for the data rate-based scaling done by the 82072 and 82077
1265*4882a593Smuzhiyun * FDC types. This parameter is ignored for other types of FDCs (i.e.
1266*4882a593Smuzhiyun * 8272a).
1267*4882a593Smuzhiyun *
1268*4882a593Smuzhiyun * Note that changing the data transfer rate has a (probably deleterious)
1269*4882a593Smuzhiyun * effect on the parameters subject to scaling for 82072/82077 FDCs, so
1270*4882a593Smuzhiyun * fdc_specify is called again after each data transfer rate
1271*4882a593Smuzhiyun * change.
1272*4882a593Smuzhiyun *
1273*4882a593Smuzhiyun * srt: 1000 to 16000 in microseconds
1274*4882a593Smuzhiyun * hut: 16 to 240 milliseconds
1275*4882a593Smuzhiyun * hlt: 2 to 254 milliseconds
1276*4882a593Smuzhiyun *
1277*4882a593Smuzhiyun * These values are rounded up to the next highest available delay time.
1278*4882a593Smuzhiyun */
fdc_specify(int fdc,int drive)1279*4882a593Smuzhiyun static void fdc_specify(int fdc, int drive)
1280*4882a593Smuzhiyun {
1281*4882a593Smuzhiyun unsigned char spec1;
1282*4882a593Smuzhiyun unsigned char spec2;
1283*4882a593Smuzhiyun unsigned long srt;
1284*4882a593Smuzhiyun unsigned long hlt;
1285*4882a593Smuzhiyun unsigned long hut;
1286*4882a593Smuzhiyun unsigned long dtr = NOMINAL_DTR;
1287*4882a593Smuzhiyun unsigned long scale_dtr = NOMINAL_DTR;
1288*4882a593Smuzhiyun int hlt_max_code = 0x7f;
1289*4882a593Smuzhiyun int hut_max_code = 0xf;
1290*4882a593Smuzhiyun
1291*4882a593Smuzhiyun if (fdc_state[fdc].need_configure &&
1292*4882a593Smuzhiyun fdc_state[fdc].version >= FDC_82072A) {
1293*4882a593Smuzhiyun fdc_configure(fdc);
1294*4882a593Smuzhiyun fdc_state[fdc].need_configure = 0;
1295*4882a593Smuzhiyun }
1296*4882a593Smuzhiyun
1297*4882a593Smuzhiyun switch (raw_cmd->rate & 0x03) {
1298*4882a593Smuzhiyun case 3:
1299*4882a593Smuzhiyun dtr = 1000;
1300*4882a593Smuzhiyun break;
1301*4882a593Smuzhiyun case 1:
1302*4882a593Smuzhiyun dtr = 300;
1303*4882a593Smuzhiyun if (fdc_state[fdc].version >= FDC_82078) {
1304*4882a593Smuzhiyun /* chose the default rate table, not the one
1305*4882a593Smuzhiyun * where 1 = 2 Mbps */
1306*4882a593Smuzhiyun output_byte(fdc, FD_DRIVESPEC);
1307*4882a593Smuzhiyun if (need_more_output(fdc) == MORE_OUTPUT) {
1308*4882a593Smuzhiyun output_byte(fdc, UNIT(drive));
1309*4882a593Smuzhiyun output_byte(fdc, 0xc0);
1310*4882a593Smuzhiyun }
1311*4882a593Smuzhiyun }
1312*4882a593Smuzhiyun break;
1313*4882a593Smuzhiyun case 2:
1314*4882a593Smuzhiyun dtr = 250;
1315*4882a593Smuzhiyun break;
1316*4882a593Smuzhiyun }
1317*4882a593Smuzhiyun
1318*4882a593Smuzhiyun if (fdc_state[fdc].version >= FDC_82072) {
1319*4882a593Smuzhiyun scale_dtr = dtr;
1320*4882a593Smuzhiyun hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
1321*4882a593Smuzhiyun hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
1322*4882a593Smuzhiyun }
1323*4882a593Smuzhiyun
1324*4882a593Smuzhiyun /* Convert step rate from microseconds to milliseconds and 4 bits */
1325*4882a593Smuzhiyun srt = 16 - DIV_ROUND_UP(drive_params[drive].srt * scale_dtr / 1000,
1326*4882a593Smuzhiyun NOMINAL_DTR);
1327*4882a593Smuzhiyun if (slow_floppy)
1328*4882a593Smuzhiyun srt = srt / 4;
1329*4882a593Smuzhiyun
1330*4882a593Smuzhiyun SUPBOUND(srt, 0xf);
1331*4882a593Smuzhiyun INFBOUND(srt, 0);
1332*4882a593Smuzhiyun
1333*4882a593Smuzhiyun hlt = DIV_ROUND_UP(drive_params[drive].hlt * scale_dtr / 2,
1334*4882a593Smuzhiyun NOMINAL_DTR);
1335*4882a593Smuzhiyun if (hlt < 0x01)
1336*4882a593Smuzhiyun hlt = 0x01;
1337*4882a593Smuzhiyun else if (hlt > 0x7f)
1338*4882a593Smuzhiyun hlt = hlt_max_code;
1339*4882a593Smuzhiyun
1340*4882a593Smuzhiyun hut = DIV_ROUND_UP(drive_params[drive].hut * scale_dtr / 16,
1341*4882a593Smuzhiyun NOMINAL_DTR);
1342*4882a593Smuzhiyun if (hut < 0x1)
1343*4882a593Smuzhiyun hut = 0x1;
1344*4882a593Smuzhiyun else if (hut > 0xf)
1345*4882a593Smuzhiyun hut = hut_max_code;
1346*4882a593Smuzhiyun
1347*4882a593Smuzhiyun spec1 = (srt << 4) | hut;
1348*4882a593Smuzhiyun spec2 = (hlt << 1) | (use_virtual_dma & 1);
1349*4882a593Smuzhiyun
1350*4882a593Smuzhiyun /* If these parameters did not change, just return with success */
1351*4882a593Smuzhiyun if (fdc_state[fdc].spec1 != spec1 ||
1352*4882a593Smuzhiyun fdc_state[fdc].spec2 != spec2) {
1353*4882a593Smuzhiyun /* Go ahead and set spec1 and spec2 */
1354*4882a593Smuzhiyun output_byte(fdc, FD_SPECIFY);
1355*4882a593Smuzhiyun output_byte(fdc, fdc_state[fdc].spec1 = spec1);
1356*4882a593Smuzhiyun output_byte(fdc, fdc_state[fdc].spec2 = spec2);
1357*4882a593Smuzhiyun }
1358*4882a593Smuzhiyun } /* fdc_specify */
1359*4882a593Smuzhiyun
1360*4882a593Smuzhiyun /* Set the FDC's data transfer rate on behalf of the specified drive.
1361*4882a593Smuzhiyun * NOTE: with 82072/82077 FDCs, changing the data rate requires a reissue
1362*4882a593Smuzhiyun * of the specify command (i.e. using the fdc_specify function).
1363*4882a593Smuzhiyun */
fdc_dtr(void)1364*4882a593Smuzhiyun static int fdc_dtr(void)
1365*4882a593Smuzhiyun {
1366*4882a593Smuzhiyun /* If data rate not already set to desired value, set it. */
1367*4882a593Smuzhiyun if ((raw_cmd->rate & 3) == fdc_state[current_fdc].dtr)
1368*4882a593Smuzhiyun return 0;
1369*4882a593Smuzhiyun
1370*4882a593Smuzhiyun /* Set dtr */
1371*4882a593Smuzhiyun fdc_outb(raw_cmd->rate & 3, current_fdc, FD_DCR);
1372*4882a593Smuzhiyun
1373*4882a593Smuzhiyun /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
1374*4882a593Smuzhiyun * need a stabilization period of several milliseconds to be
1375*4882a593Smuzhiyun * enforced after data rate changes before R/W operations.
1376*4882a593Smuzhiyun * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
1377*4882a593Smuzhiyun */
1378*4882a593Smuzhiyun fdc_state[current_fdc].dtr = raw_cmd->rate & 3;
1379*4882a593Smuzhiyun return fd_wait_for_completion(jiffies + 2UL * HZ / 100, floppy_ready);
1380*4882a593Smuzhiyun } /* fdc_dtr */
1381*4882a593Smuzhiyun
tell_sector(void)1382*4882a593Smuzhiyun static void tell_sector(void)
1383*4882a593Smuzhiyun {
1384*4882a593Smuzhiyun pr_cont(": track %d, head %d, sector %d, size %d",
1385*4882a593Smuzhiyun reply_buffer[R_TRACK], reply_buffer[R_HEAD],
1386*4882a593Smuzhiyun reply_buffer[R_SECTOR],
1387*4882a593Smuzhiyun reply_buffer[R_SIZECODE]);
1388*4882a593Smuzhiyun } /* tell_sector */
1389*4882a593Smuzhiyun
print_errors(void)1390*4882a593Smuzhiyun static void print_errors(void)
1391*4882a593Smuzhiyun {
1392*4882a593Smuzhiyun DPRINT("");
1393*4882a593Smuzhiyun if (reply_buffer[ST0] & ST0_ECE) {
1394*4882a593Smuzhiyun pr_cont("Recalibrate failed!");
1395*4882a593Smuzhiyun } else if (reply_buffer[ST2] & ST2_CRC) {
1396*4882a593Smuzhiyun pr_cont("data CRC error");
1397*4882a593Smuzhiyun tell_sector();
1398*4882a593Smuzhiyun } else if (reply_buffer[ST1] & ST1_CRC) {
1399*4882a593Smuzhiyun pr_cont("CRC error");
1400*4882a593Smuzhiyun tell_sector();
1401*4882a593Smuzhiyun } else if ((reply_buffer[ST1] & (ST1_MAM | ST1_ND)) ||
1402*4882a593Smuzhiyun (reply_buffer[ST2] & ST2_MAM)) {
1403*4882a593Smuzhiyun if (!probing) {
1404*4882a593Smuzhiyun pr_cont("sector not found");
1405*4882a593Smuzhiyun tell_sector();
1406*4882a593Smuzhiyun } else
1407*4882a593Smuzhiyun pr_cont("probe failed...");
1408*4882a593Smuzhiyun } else if (reply_buffer[ST2] & ST2_WC) { /* seek error */
1409*4882a593Smuzhiyun pr_cont("wrong cylinder");
1410*4882a593Smuzhiyun } else if (reply_buffer[ST2] & ST2_BC) { /* cylinder marked as bad */
1411*4882a593Smuzhiyun pr_cont("bad cylinder");
1412*4882a593Smuzhiyun } else {
1413*4882a593Smuzhiyun pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
1414*4882a593Smuzhiyun reply_buffer[ST0], reply_buffer[ST1],
1415*4882a593Smuzhiyun reply_buffer[ST2]);
1416*4882a593Smuzhiyun tell_sector();
1417*4882a593Smuzhiyun }
1418*4882a593Smuzhiyun pr_cont("\n");
1419*4882a593Smuzhiyun }
1420*4882a593Smuzhiyun
1421*4882a593Smuzhiyun /*
1422*4882a593Smuzhiyun * OK, this error interpreting routine is called after a
1423*4882a593Smuzhiyun * DMA read/write has succeeded
1424*4882a593Smuzhiyun * or failed, so we check the results, and copy any buffers.
1425*4882a593Smuzhiyun * hhb: Added better error reporting.
1426*4882a593Smuzhiyun * ak: Made this into a separate routine.
1427*4882a593Smuzhiyun */
interpret_errors(void)1428*4882a593Smuzhiyun static int interpret_errors(void)
1429*4882a593Smuzhiyun {
1430*4882a593Smuzhiyun char bad;
1431*4882a593Smuzhiyun
1432*4882a593Smuzhiyun if (inr != 7) {
1433*4882a593Smuzhiyun DPRINT("-- FDC reply error\n");
1434*4882a593Smuzhiyun fdc_state[current_fdc].reset = 1;
1435*4882a593Smuzhiyun return 1;
1436*4882a593Smuzhiyun }
1437*4882a593Smuzhiyun
1438*4882a593Smuzhiyun /* check IC to find cause of interrupt */
1439*4882a593Smuzhiyun switch (reply_buffer[ST0] & ST0_INTR) {
1440*4882a593Smuzhiyun case 0x40: /* error occurred during command execution */
1441*4882a593Smuzhiyun if (reply_buffer[ST1] & ST1_EOC)
1442*4882a593Smuzhiyun return 0; /* occurs with pseudo-DMA */
1443*4882a593Smuzhiyun bad = 1;
1444*4882a593Smuzhiyun if (reply_buffer[ST1] & ST1_WP) {
1445*4882a593Smuzhiyun DPRINT("Drive is write protected\n");
1446*4882a593Smuzhiyun clear_bit(FD_DISK_WRITABLE_BIT,
1447*4882a593Smuzhiyun &drive_state[current_drive].flags);
1448*4882a593Smuzhiyun cont->done(0);
1449*4882a593Smuzhiyun bad = 2;
1450*4882a593Smuzhiyun } else if (reply_buffer[ST1] & ST1_ND) {
1451*4882a593Smuzhiyun set_bit(FD_NEED_TWADDLE_BIT,
1452*4882a593Smuzhiyun &drive_state[current_drive].flags);
1453*4882a593Smuzhiyun } else if (reply_buffer[ST1] & ST1_OR) {
1454*4882a593Smuzhiyun if (drive_params[current_drive].flags & FTD_MSG)
1455*4882a593Smuzhiyun DPRINT("Over/Underrun - retrying\n");
1456*4882a593Smuzhiyun bad = 0;
1457*4882a593Smuzhiyun } else if (floppy_errors >= drive_params[current_drive].max_errors.reporting) {
1458*4882a593Smuzhiyun print_errors();
1459*4882a593Smuzhiyun }
1460*4882a593Smuzhiyun if (reply_buffer[ST2] & ST2_WC || reply_buffer[ST2] & ST2_BC)
1461*4882a593Smuzhiyun /* wrong cylinder => recal */
1462*4882a593Smuzhiyun drive_state[current_drive].track = NEED_2_RECAL;
1463*4882a593Smuzhiyun return bad;
1464*4882a593Smuzhiyun case 0x80: /* invalid command given */
1465*4882a593Smuzhiyun DPRINT("Invalid FDC command given!\n");
1466*4882a593Smuzhiyun cont->done(0);
1467*4882a593Smuzhiyun return 2;
1468*4882a593Smuzhiyun case 0xc0:
1469*4882a593Smuzhiyun DPRINT("Abnormal termination caused by polling\n");
1470*4882a593Smuzhiyun cont->error();
1471*4882a593Smuzhiyun return 2;
1472*4882a593Smuzhiyun default: /* (0) Normal command termination */
1473*4882a593Smuzhiyun return 0;
1474*4882a593Smuzhiyun }
1475*4882a593Smuzhiyun }
1476*4882a593Smuzhiyun
1477*4882a593Smuzhiyun /*
1478*4882a593Smuzhiyun * This routine is called when everything should be correctly set up
1479*4882a593Smuzhiyun * for the transfer (i.e. floppy motor is on, the correct floppy is
1480*4882a593Smuzhiyun * selected, and the head is sitting on the right track).
1481*4882a593Smuzhiyun */
setup_rw_floppy(void)1482*4882a593Smuzhiyun static void setup_rw_floppy(void)
1483*4882a593Smuzhiyun {
1484*4882a593Smuzhiyun int i;
1485*4882a593Smuzhiyun int r;
1486*4882a593Smuzhiyun int flags;
1487*4882a593Smuzhiyun unsigned long ready_date;
1488*4882a593Smuzhiyun void (*function)(void);
1489*4882a593Smuzhiyun
1490*4882a593Smuzhiyun flags = raw_cmd->flags;
1491*4882a593Smuzhiyun if (flags & (FD_RAW_READ | FD_RAW_WRITE))
1492*4882a593Smuzhiyun flags |= FD_RAW_INTR;
1493*4882a593Smuzhiyun
1494*4882a593Smuzhiyun if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
1495*4882a593Smuzhiyun ready_date = drive_state[current_drive].spinup_date + drive_params[current_drive].spinup;
1496*4882a593Smuzhiyun /* If spinup will take a long time, rerun scandrives
1497*4882a593Smuzhiyun * again just before spinup completion. Beware that
1498*4882a593Smuzhiyun * after scandrives, we must again wait for selection.
1499*4882a593Smuzhiyun */
1500*4882a593Smuzhiyun if (time_after(ready_date, jiffies + drive_params[current_drive].select_delay)) {
1501*4882a593Smuzhiyun ready_date -= drive_params[current_drive].select_delay;
1502*4882a593Smuzhiyun function = floppy_start;
1503*4882a593Smuzhiyun } else
1504*4882a593Smuzhiyun function = setup_rw_floppy;
1505*4882a593Smuzhiyun
1506*4882a593Smuzhiyun /* wait until the floppy is spinning fast enough */
1507*4882a593Smuzhiyun if (fd_wait_for_completion(ready_date, function))
1508*4882a593Smuzhiyun return;
1509*4882a593Smuzhiyun }
1510*4882a593Smuzhiyun if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE))
1511*4882a593Smuzhiyun setup_DMA();
1512*4882a593Smuzhiyun
1513*4882a593Smuzhiyun if (flags & FD_RAW_INTR)
1514*4882a593Smuzhiyun do_floppy = main_command_interrupt;
1515*4882a593Smuzhiyun
1516*4882a593Smuzhiyun r = 0;
1517*4882a593Smuzhiyun for (i = 0; i < raw_cmd->cmd_count; i++)
1518*4882a593Smuzhiyun r |= output_byte(current_fdc, raw_cmd->fullcmd[i]);
1519*4882a593Smuzhiyun
1520*4882a593Smuzhiyun debugt(__func__, "rw_command");
1521*4882a593Smuzhiyun
1522*4882a593Smuzhiyun if (r) {
1523*4882a593Smuzhiyun cont->error();
1524*4882a593Smuzhiyun reset_fdc();
1525*4882a593Smuzhiyun return;
1526*4882a593Smuzhiyun }
1527*4882a593Smuzhiyun
1528*4882a593Smuzhiyun if (!(flags & FD_RAW_INTR)) {
1529*4882a593Smuzhiyun inr = result(current_fdc);
1530*4882a593Smuzhiyun cont->interrupt();
1531*4882a593Smuzhiyun } else if (flags & FD_RAW_NEED_DISK)
1532*4882a593Smuzhiyun fd_watchdog();
1533*4882a593Smuzhiyun }
1534*4882a593Smuzhiyun
1535*4882a593Smuzhiyun static int blind_seek;
1536*4882a593Smuzhiyun
1537*4882a593Smuzhiyun /*
1538*4882a593Smuzhiyun * This is the routine called after every seek (or recalibrate) interrupt
1539*4882a593Smuzhiyun * from the floppy controller.
1540*4882a593Smuzhiyun */
seek_interrupt(void)1541*4882a593Smuzhiyun static void seek_interrupt(void)
1542*4882a593Smuzhiyun {
1543*4882a593Smuzhiyun debugt(__func__, "");
1544*4882a593Smuzhiyun if (inr != 2 || (reply_buffer[ST0] & 0xF8) != 0x20) {
1545*4882a593Smuzhiyun DPRINT("seek failed\n");
1546*4882a593Smuzhiyun drive_state[current_drive].track = NEED_2_RECAL;
1547*4882a593Smuzhiyun cont->error();
1548*4882a593Smuzhiyun cont->redo();
1549*4882a593Smuzhiyun return;
1550*4882a593Smuzhiyun }
1551*4882a593Smuzhiyun if (drive_state[current_drive].track >= 0 &&
1552*4882a593Smuzhiyun drive_state[current_drive].track != reply_buffer[ST1] &&
1553*4882a593Smuzhiyun !blind_seek) {
1554*4882a593Smuzhiyun debug_dcl(drive_params[current_drive].flags,
1555*4882a593Smuzhiyun "clearing NEWCHANGE flag because of effective seek\n");
1556*4882a593Smuzhiyun debug_dcl(drive_params[current_drive].flags, "jiffies=%lu\n",
1557*4882a593Smuzhiyun jiffies);
1558*4882a593Smuzhiyun clear_bit(FD_DISK_NEWCHANGE_BIT,
1559*4882a593Smuzhiyun &drive_state[current_drive].flags);
1560*4882a593Smuzhiyun /* effective seek */
1561*4882a593Smuzhiyun drive_state[current_drive].select_date = jiffies;
1562*4882a593Smuzhiyun }
1563*4882a593Smuzhiyun drive_state[current_drive].track = reply_buffer[ST1];
1564*4882a593Smuzhiyun floppy_ready();
1565*4882a593Smuzhiyun }
1566*4882a593Smuzhiyun
check_wp(int fdc,int drive)1567*4882a593Smuzhiyun static void check_wp(int fdc, int drive)
1568*4882a593Smuzhiyun {
1569*4882a593Smuzhiyun if (test_bit(FD_VERIFY_BIT, &drive_state[drive].flags)) {
1570*4882a593Smuzhiyun /* check write protection */
1571*4882a593Smuzhiyun output_byte(fdc, FD_GETSTATUS);
1572*4882a593Smuzhiyun output_byte(fdc, UNIT(drive));
1573*4882a593Smuzhiyun if (result(fdc) != 1) {
1574*4882a593Smuzhiyun fdc_state[fdc].reset = 1;
1575*4882a593Smuzhiyun return;
1576*4882a593Smuzhiyun }
1577*4882a593Smuzhiyun clear_bit(FD_VERIFY_BIT, &drive_state[drive].flags);
1578*4882a593Smuzhiyun clear_bit(FD_NEED_TWADDLE_BIT,
1579*4882a593Smuzhiyun &drive_state[drive].flags);
1580*4882a593Smuzhiyun debug_dcl(drive_params[drive].flags,
1581*4882a593Smuzhiyun "checking whether disk is write protected\n");
1582*4882a593Smuzhiyun debug_dcl(drive_params[drive].flags, "wp=%x\n",
1583*4882a593Smuzhiyun reply_buffer[ST3] & 0x40);
1584*4882a593Smuzhiyun if (!(reply_buffer[ST3] & 0x40))
1585*4882a593Smuzhiyun set_bit(FD_DISK_WRITABLE_BIT,
1586*4882a593Smuzhiyun &drive_state[drive].flags);
1587*4882a593Smuzhiyun else
1588*4882a593Smuzhiyun clear_bit(FD_DISK_WRITABLE_BIT,
1589*4882a593Smuzhiyun &drive_state[drive].flags);
1590*4882a593Smuzhiyun }
1591*4882a593Smuzhiyun }
1592*4882a593Smuzhiyun
seek_floppy(void)1593*4882a593Smuzhiyun static void seek_floppy(void)
1594*4882a593Smuzhiyun {
1595*4882a593Smuzhiyun int track;
1596*4882a593Smuzhiyun
1597*4882a593Smuzhiyun blind_seek = 0;
1598*4882a593Smuzhiyun
1599*4882a593Smuzhiyun debug_dcl(drive_params[current_drive].flags,
1600*4882a593Smuzhiyun "calling disk change from %s\n", __func__);
1601*4882a593Smuzhiyun
1602*4882a593Smuzhiyun if (!test_bit(FD_DISK_NEWCHANGE_BIT, &drive_state[current_drive].flags) &&
1603*4882a593Smuzhiyun disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
1604*4882a593Smuzhiyun /* the media changed flag should be cleared after the seek.
1605*4882a593Smuzhiyun * If it isn't, this means that there is really no disk in
1606*4882a593Smuzhiyun * the drive.
1607*4882a593Smuzhiyun */
1608*4882a593Smuzhiyun set_bit(FD_DISK_CHANGED_BIT,
1609*4882a593Smuzhiyun &drive_state[current_drive].flags);
1610*4882a593Smuzhiyun cont->done(0);
1611*4882a593Smuzhiyun cont->redo();
1612*4882a593Smuzhiyun return;
1613*4882a593Smuzhiyun }
1614*4882a593Smuzhiyun if (drive_state[current_drive].track <= NEED_1_RECAL) {
1615*4882a593Smuzhiyun recalibrate_floppy();
1616*4882a593Smuzhiyun return;
1617*4882a593Smuzhiyun } else if (test_bit(FD_DISK_NEWCHANGE_BIT, &drive_state[current_drive].flags) &&
1618*4882a593Smuzhiyun (raw_cmd->flags & FD_RAW_NEED_DISK) &&
1619*4882a593Smuzhiyun (drive_state[current_drive].track <= NO_TRACK || drive_state[current_drive].track == raw_cmd->track)) {
1620*4882a593Smuzhiyun /* we seek to clear the media-changed condition. Does anybody
1621*4882a593Smuzhiyun * know a more elegant way, which works on all drives? */
1622*4882a593Smuzhiyun if (raw_cmd->track)
1623*4882a593Smuzhiyun track = raw_cmd->track - 1;
1624*4882a593Smuzhiyun else {
1625*4882a593Smuzhiyun if (drive_params[current_drive].flags & FD_SILENT_DCL_CLEAR) {
1626*4882a593Smuzhiyun set_dor(current_fdc, ~(0x10 << UNIT(current_drive)), 0);
1627*4882a593Smuzhiyun blind_seek = 1;
1628*4882a593Smuzhiyun raw_cmd->flags |= FD_RAW_NEED_SEEK;
1629*4882a593Smuzhiyun }
1630*4882a593Smuzhiyun track = 1;
1631*4882a593Smuzhiyun }
1632*4882a593Smuzhiyun } else {
1633*4882a593Smuzhiyun check_wp(current_fdc, current_drive);
1634*4882a593Smuzhiyun if (raw_cmd->track != drive_state[current_drive].track &&
1635*4882a593Smuzhiyun (raw_cmd->flags & FD_RAW_NEED_SEEK))
1636*4882a593Smuzhiyun track = raw_cmd->track;
1637*4882a593Smuzhiyun else {
1638*4882a593Smuzhiyun setup_rw_floppy();
1639*4882a593Smuzhiyun return;
1640*4882a593Smuzhiyun }
1641*4882a593Smuzhiyun }
1642*4882a593Smuzhiyun
1643*4882a593Smuzhiyun do_floppy = seek_interrupt;
1644*4882a593Smuzhiyun output_byte(current_fdc, FD_SEEK);
1645*4882a593Smuzhiyun output_byte(current_fdc, UNIT(current_drive));
1646*4882a593Smuzhiyun if (output_byte(current_fdc, track) < 0) {
1647*4882a593Smuzhiyun reset_fdc();
1648*4882a593Smuzhiyun return;
1649*4882a593Smuzhiyun }
1650*4882a593Smuzhiyun debugt(__func__, "");
1651*4882a593Smuzhiyun }
1652*4882a593Smuzhiyun
recal_interrupt(void)1653*4882a593Smuzhiyun static void recal_interrupt(void)
1654*4882a593Smuzhiyun {
1655*4882a593Smuzhiyun debugt(__func__, "");
1656*4882a593Smuzhiyun if (inr != 2)
1657*4882a593Smuzhiyun fdc_state[current_fdc].reset = 1;
1658*4882a593Smuzhiyun else if (reply_buffer[ST0] & ST0_ECE) {
1659*4882a593Smuzhiyun switch (drive_state[current_drive].track) {
1660*4882a593Smuzhiyun case NEED_1_RECAL:
1661*4882a593Smuzhiyun debugt(__func__, "need 1 recal");
1662*4882a593Smuzhiyun /* after a second recalibrate, we still haven't
1663*4882a593Smuzhiyun * reached track 0. Probably no drive. Raise an
1664*4882a593Smuzhiyun * error, as failing immediately might upset
1665*4882a593Smuzhiyun * computers possessed by the Devil :-) */
1666*4882a593Smuzhiyun cont->error();
1667*4882a593Smuzhiyun cont->redo();
1668*4882a593Smuzhiyun return;
1669*4882a593Smuzhiyun case NEED_2_RECAL:
1670*4882a593Smuzhiyun debugt(__func__, "need 2 recal");
1671*4882a593Smuzhiyun /* If we already did a recalibrate,
1672*4882a593Smuzhiyun * and we are not at track 0, this
1673*4882a593Smuzhiyun * means we have moved. (The only way
1674*4882a593Smuzhiyun * not to move at recalibration is to
1675*4882a593Smuzhiyun * be already at track 0.) Clear the
1676*4882a593Smuzhiyun * new change flag */
1677*4882a593Smuzhiyun debug_dcl(drive_params[current_drive].flags,
1678*4882a593Smuzhiyun "clearing NEWCHANGE flag because of second recalibrate\n");
1679*4882a593Smuzhiyun
1680*4882a593Smuzhiyun clear_bit(FD_DISK_NEWCHANGE_BIT,
1681*4882a593Smuzhiyun &drive_state[current_drive].flags);
1682*4882a593Smuzhiyun drive_state[current_drive].select_date = jiffies;
1683*4882a593Smuzhiyun fallthrough;
1684*4882a593Smuzhiyun default:
1685*4882a593Smuzhiyun debugt(__func__, "default");
1686*4882a593Smuzhiyun /* Recalibrate moves the head by at
1687*4882a593Smuzhiyun * most 80 steps. If after one
1688*4882a593Smuzhiyun * recalibrate we don't have reached
1689*4882a593Smuzhiyun * track 0, this might mean that we
1690*4882a593Smuzhiyun * started beyond track 80. Try
1691*4882a593Smuzhiyun * again. */
1692*4882a593Smuzhiyun drive_state[current_drive].track = NEED_1_RECAL;
1693*4882a593Smuzhiyun break;
1694*4882a593Smuzhiyun }
1695*4882a593Smuzhiyun } else
1696*4882a593Smuzhiyun drive_state[current_drive].track = reply_buffer[ST1];
1697*4882a593Smuzhiyun floppy_ready();
1698*4882a593Smuzhiyun }
1699*4882a593Smuzhiyun
print_result(char * message,int inr)1700*4882a593Smuzhiyun static void print_result(char *message, int inr)
1701*4882a593Smuzhiyun {
1702*4882a593Smuzhiyun int i;
1703*4882a593Smuzhiyun
1704*4882a593Smuzhiyun DPRINT("%s ", message);
1705*4882a593Smuzhiyun if (inr >= 0)
1706*4882a593Smuzhiyun for (i = 0; i < inr; i++)
1707*4882a593Smuzhiyun pr_cont("repl[%d]=%x ", i, reply_buffer[i]);
1708*4882a593Smuzhiyun pr_cont("\n");
1709*4882a593Smuzhiyun }
1710*4882a593Smuzhiyun
1711*4882a593Smuzhiyun /* interrupt handler. Note that this can be called externally on the Sparc */
floppy_interrupt(int irq,void * dev_id)1712*4882a593Smuzhiyun irqreturn_t floppy_interrupt(int irq, void *dev_id)
1713*4882a593Smuzhiyun {
1714*4882a593Smuzhiyun int do_print;
1715*4882a593Smuzhiyun unsigned long f;
1716*4882a593Smuzhiyun void (*handler)(void) = do_floppy;
1717*4882a593Smuzhiyun
1718*4882a593Smuzhiyun lasthandler = handler;
1719*4882a593Smuzhiyun interruptjiffies = jiffies;
1720*4882a593Smuzhiyun
1721*4882a593Smuzhiyun f = claim_dma_lock();
1722*4882a593Smuzhiyun fd_disable_dma();
1723*4882a593Smuzhiyun release_dma_lock(f);
1724*4882a593Smuzhiyun
1725*4882a593Smuzhiyun do_floppy = NULL;
1726*4882a593Smuzhiyun if (current_fdc >= N_FDC || fdc_state[current_fdc].address == -1) {
1727*4882a593Smuzhiyun /* we don't even know which FDC is the culprit */
1728*4882a593Smuzhiyun pr_info("DOR0=%x\n", fdc_state[0].dor);
1729*4882a593Smuzhiyun pr_info("floppy interrupt on bizarre fdc %d\n", current_fdc);
1730*4882a593Smuzhiyun pr_info("handler=%ps\n", handler);
1731*4882a593Smuzhiyun is_alive(__func__, "bizarre fdc");
1732*4882a593Smuzhiyun return IRQ_NONE;
1733*4882a593Smuzhiyun }
1734*4882a593Smuzhiyun
1735*4882a593Smuzhiyun fdc_state[current_fdc].reset = 0;
1736*4882a593Smuzhiyun /* We have to clear the reset flag here, because apparently on boxes
1737*4882a593Smuzhiyun * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
1738*4882a593Smuzhiyun * emit SENSEI's to clear the interrupt line. And fdc_state[fdc].reset
1739*4882a593Smuzhiyun * blocks the emission of the SENSEI's.
1740*4882a593Smuzhiyun * It is OK to emit floppy commands because we are in an interrupt
1741*4882a593Smuzhiyun * handler here, and thus we have to fear no interference of other
1742*4882a593Smuzhiyun * activity.
1743*4882a593Smuzhiyun */
1744*4882a593Smuzhiyun
1745*4882a593Smuzhiyun do_print = !handler && print_unex && initialized;
1746*4882a593Smuzhiyun
1747*4882a593Smuzhiyun inr = result(current_fdc);
1748*4882a593Smuzhiyun if (do_print)
1749*4882a593Smuzhiyun print_result("unexpected interrupt", inr);
1750*4882a593Smuzhiyun if (inr == 0) {
1751*4882a593Smuzhiyun int max_sensei = 4;
1752*4882a593Smuzhiyun do {
1753*4882a593Smuzhiyun output_byte(current_fdc, FD_SENSEI);
1754*4882a593Smuzhiyun inr = result(current_fdc);
1755*4882a593Smuzhiyun if (do_print)
1756*4882a593Smuzhiyun print_result("sensei", inr);
1757*4882a593Smuzhiyun max_sensei--;
1758*4882a593Smuzhiyun } while ((reply_buffer[ST0] & 0x83) != UNIT(current_drive) &&
1759*4882a593Smuzhiyun inr == 2 && max_sensei);
1760*4882a593Smuzhiyun }
1761*4882a593Smuzhiyun if (!handler) {
1762*4882a593Smuzhiyun fdc_state[current_fdc].reset = 1;
1763*4882a593Smuzhiyun return IRQ_NONE;
1764*4882a593Smuzhiyun }
1765*4882a593Smuzhiyun schedule_bh(handler);
1766*4882a593Smuzhiyun is_alive(__func__, "normal interrupt end");
1767*4882a593Smuzhiyun
1768*4882a593Smuzhiyun /* FIXME! Was it really for us? */
1769*4882a593Smuzhiyun return IRQ_HANDLED;
1770*4882a593Smuzhiyun }
1771*4882a593Smuzhiyun
recalibrate_floppy(void)1772*4882a593Smuzhiyun static void recalibrate_floppy(void)
1773*4882a593Smuzhiyun {
1774*4882a593Smuzhiyun debugt(__func__, "");
1775*4882a593Smuzhiyun do_floppy = recal_interrupt;
1776*4882a593Smuzhiyun output_byte(current_fdc, FD_RECALIBRATE);
1777*4882a593Smuzhiyun if (output_byte(current_fdc, UNIT(current_drive)) < 0)
1778*4882a593Smuzhiyun reset_fdc();
1779*4882a593Smuzhiyun }
1780*4882a593Smuzhiyun
1781*4882a593Smuzhiyun /*
1782*4882a593Smuzhiyun * Must do 4 FD_SENSEIs after reset because of ``drive polling''.
1783*4882a593Smuzhiyun */
reset_interrupt(void)1784*4882a593Smuzhiyun static void reset_interrupt(void)
1785*4882a593Smuzhiyun {
1786*4882a593Smuzhiyun debugt(__func__, "");
1787*4882a593Smuzhiyun result(current_fdc); /* get the status ready for set_fdc */
1788*4882a593Smuzhiyun if (fdc_state[current_fdc].reset) {
1789*4882a593Smuzhiyun pr_info("reset set in interrupt, calling %ps\n", cont->error);
1790*4882a593Smuzhiyun cont->error(); /* a reset just after a reset. BAD! */
1791*4882a593Smuzhiyun }
1792*4882a593Smuzhiyun cont->redo();
1793*4882a593Smuzhiyun }
1794*4882a593Smuzhiyun
1795*4882a593Smuzhiyun /*
1796*4882a593Smuzhiyun * reset is done by pulling bit 2 of DOR low for a while (old FDCs),
1797*4882a593Smuzhiyun * or by setting the self clearing bit 7 of STATUS (newer FDCs).
1798*4882a593Smuzhiyun * This WILL trigger an interrupt, causing the handlers in the current
1799*4882a593Smuzhiyun * cont's ->redo() to be called via reset_interrupt().
1800*4882a593Smuzhiyun */
reset_fdc(void)1801*4882a593Smuzhiyun static void reset_fdc(void)
1802*4882a593Smuzhiyun {
1803*4882a593Smuzhiyun unsigned long flags;
1804*4882a593Smuzhiyun
1805*4882a593Smuzhiyun do_floppy = reset_interrupt;
1806*4882a593Smuzhiyun fdc_state[current_fdc].reset = 0;
1807*4882a593Smuzhiyun reset_fdc_info(current_fdc, 0);
1808*4882a593Smuzhiyun
1809*4882a593Smuzhiyun /* Pseudo-DMA may intercept 'reset finished' interrupt. */
1810*4882a593Smuzhiyun /* Irrelevant for systems with true DMA (i386). */
1811*4882a593Smuzhiyun
1812*4882a593Smuzhiyun flags = claim_dma_lock();
1813*4882a593Smuzhiyun fd_disable_dma();
1814*4882a593Smuzhiyun release_dma_lock(flags);
1815*4882a593Smuzhiyun
1816*4882a593Smuzhiyun if (fdc_state[current_fdc].version >= FDC_82072A)
1817*4882a593Smuzhiyun fdc_outb(0x80 | (fdc_state[current_fdc].dtr & 3),
1818*4882a593Smuzhiyun current_fdc, FD_STATUS);
1819*4882a593Smuzhiyun else {
1820*4882a593Smuzhiyun fdc_outb(fdc_state[current_fdc].dor & ~0x04, current_fdc, FD_DOR);
1821*4882a593Smuzhiyun udelay(FD_RESET_DELAY);
1822*4882a593Smuzhiyun fdc_outb(fdc_state[current_fdc].dor, current_fdc, FD_DOR);
1823*4882a593Smuzhiyun }
1824*4882a593Smuzhiyun }
1825*4882a593Smuzhiyun
show_floppy(int fdc)1826*4882a593Smuzhiyun static void show_floppy(int fdc)
1827*4882a593Smuzhiyun {
1828*4882a593Smuzhiyun int i;
1829*4882a593Smuzhiyun
1830*4882a593Smuzhiyun pr_info("\n");
1831*4882a593Smuzhiyun pr_info("floppy driver state\n");
1832*4882a593Smuzhiyun pr_info("-------------------\n");
1833*4882a593Smuzhiyun pr_info("now=%lu last interrupt=%lu diff=%lu last called handler=%ps\n",
1834*4882a593Smuzhiyun jiffies, interruptjiffies, jiffies - interruptjiffies,
1835*4882a593Smuzhiyun lasthandler);
1836*4882a593Smuzhiyun
1837*4882a593Smuzhiyun pr_info("timeout_message=%s\n", timeout_message);
1838*4882a593Smuzhiyun pr_info("last output bytes:\n");
1839*4882a593Smuzhiyun for (i = 0; i < OLOGSIZE; i++)
1840*4882a593Smuzhiyun pr_info("%2x %2x %lu\n",
1841*4882a593Smuzhiyun output_log[(i + output_log_pos) % OLOGSIZE].data,
1842*4882a593Smuzhiyun output_log[(i + output_log_pos) % OLOGSIZE].status,
1843*4882a593Smuzhiyun output_log[(i + output_log_pos) % OLOGSIZE].jiffies);
1844*4882a593Smuzhiyun pr_info("last result at %lu\n", resultjiffies);
1845*4882a593Smuzhiyun pr_info("last redo_fd_request at %lu\n", lastredo);
1846*4882a593Smuzhiyun print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
1847*4882a593Smuzhiyun reply_buffer, resultsize, true);
1848*4882a593Smuzhiyun
1849*4882a593Smuzhiyun pr_info("status=%x\n", fdc_inb(fdc, FD_STATUS));
1850*4882a593Smuzhiyun pr_info("fdc_busy=%lu\n", fdc_busy);
1851*4882a593Smuzhiyun if (do_floppy)
1852*4882a593Smuzhiyun pr_info("do_floppy=%ps\n", do_floppy);
1853*4882a593Smuzhiyun if (work_pending(&floppy_work))
1854*4882a593Smuzhiyun pr_info("floppy_work.func=%ps\n", floppy_work.func);
1855*4882a593Smuzhiyun if (delayed_work_pending(&fd_timer))
1856*4882a593Smuzhiyun pr_info("delayed work.function=%p expires=%ld\n",
1857*4882a593Smuzhiyun fd_timer.work.func,
1858*4882a593Smuzhiyun fd_timer.timer.expires - jiffies);
1859*4882a593Smuzhiyun if (delayed_work_pending(&fd_timeout))
1860*4882a593Smuzhiyun pr_info("timer_function=%p expires=%ld\n",
1861*4882a593Smuzhiyun fd_timeout.work.func,
1862*4882a593Smuzhiyun fd_timeout.timer.expires - jiffies);
1863*4882a593Smuzhiyun
1864*4882a593Smuzhiyun pr_info("cont=%p\n", cont);
1865*4882a593Smuzhiyun pr_info("current_req=%p\n", current_req);
1866*4882a593Smuzhiyun pr_info("command_status=%d\n", command_status);
1867*4882a593Smuzhiyun pr_info("\n");
1868*4882a593Smuzhiyun }
1869*4882a593Smuzhiyun
floppy_shutdown(struct work_struct * arg)1870*4882a593Smuzhiyun static void floppy_shutdown(struct work_struct *arg)
1871*4882a593Smuzhiyun {
1872*4882a593Smuzhiyun unsigned long flags;
1873*4882a593Smuzhiyun
1874*4882a593Smuzhiyun if (initialized)
1875*4882a593Smuzhiyun show_floppy(current_fdc);
1876*4882a593Smuzhiyun cancel_activity();
1877*4882a593Smuzhiyun
1878*4882a593Smuzhiyun flags = claim_dma_lock();
1879*4882a593Smuzhiyun fd_disable_dma();
1880*4882a593Smuzhiyun release_dma_lock(flags);
1881*4882a593Smuzhiyun
1882*4882a593Smuzhiyun /* avoid dma going to a random drive after shutdown */
1883*4882a593Smuzhiyun
1884*4882a593Smuzhiyun if (initialized)
1885*4882a593Smuzhiyun DPRINT("floppy timeout called\n");
1886*4882a593Smuzhiyun fdc_state[current_fdc].reset = 1;
1887*4882a593Smuzhiyun if (cont) {
1888*4882a593Smuzhiyun cont->done(0);
1889*4882a593Smuzhiyun cont->redo(); /* this will recall reset when needed */
1890*4882a593Smuzhiyun } else {
1891*4882a593Smuzhiyun pr_info("no cont in shutdown!\n");
1892*4882a593Smuzhiyun process_fd_request();
1893*4882a593Smuzhiyun }
1894*4882a593Smuzhiyun is_alive(__func__, "");
1895*4882a593Smuzhiyun }
1896*4882a593Smuzhiyun
1897*4882a593Smuzhiyun /* start motor, check media-changed condition and write protection */
start_motor(void (* function)(void))1898*4882a593Smuzhiyun static int start_motor(void (*function)(void))
1899*4882a593Smuzhiyun {
1900*4882a593Smuzhiyun int mask;
1901*4882a593Smuzhiyun int data;
1902*4882a593Smuzhiyun
1903*4882a593Smuzhiyun mask = 0xfc;
1904*4882a593Smuzhiyun data = UNIT(current_drive);
1905*4882a593Smuzhiyun if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
1906*4882a593Smuzhiyun if (!(fdc_state[current_fdc].dor & (0x10 << UNIT(current_drive)))) {
1907*4882a593Smuzhiyun set_debugt();
1908*4882a593Smuzhiyun /* no read since this drive is running */
1909*4882a593Smuzhiyun drive_state[current_drive].first_read_date = 0;
1910*4882a593Smuzhiyun /* note motor start time if motor is not yet running */
1911*4882a593Smuzhiyun drive_state[current_drive].spinup_date = jiffies;
1912*4882a593Smuzhiyun data |= (0x10 << UNIT(current_drive));
1913*4882a593Smuzhiyun }
1914*4882a593Smuzhiyun } else if (fdc_state[current_fdc].dor & (0x10 << UNIT(current_drive)))
1915*4882a593Smuzhiyun mask &= ~(0x10 << UNIT(current_drive));
1916*4882a593Smuzhiyun
1917*4882a593Smuzhiyun /* starts motor and selects floppy */
1918*4882a593Smuzhiyun del_timer(motor_off_timer + current_drive);
1919*4882a593Smuzhiyun set_dor(current_fdc, mask, data);
1920*4882a593Smuzhiyun
1921*4882a593Smuzhiyun /* wait_for_completion also schedules reset if needed. */
1922*4882a593Smuzhiyun return fd_wait_for_completion(drive_state[current_drive].select_date + drive_params[current_drive].select_delay,
1923*4882a593Smuzhiyun function);
1924*4882a593Smuzhiyun }
1925*4882a593Smuzhiyun
floppy_ready(void)1926*4882a593Smuzhiyun static void floppy_ready(void)
1927*4882a593Smuzhiyun {
1928*4882a593Smuzhiyun if (fdc_state[current_fdc].reset) {
1929*4882a593Smuzhiyun reset_fdc();
1930*4882a593Smuzhiyun return;
1931*4882a593Smuzhiyun }
1932*4882a593Smuzhiyun if (start_motor(floppy_ready))
1933*4882a593Smuzhiyun return;
1934*4882a593Smuzhiyun if (fdc_dtr())
1935*4882a593Smuzhiyun return;
1936*4882a593Smuzhiyun
1937*4882a593Smuzhiyun debug_dcl(drive_params[current_drive].flags,
1938*4882a593Smuzhiyun "calling disk change from floppy_ready\n");
1939*4882a593Smuzhiyun if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
1940*4882a593Smuzhiyun disk_change(current_drive) && !drive_params[current_drive].select_delay)
1941*4882a593Smuzhiyun twaddle(current_fdc, current_drive); /* this clears the dcl on certain
1942*4882a593Smuzhiyun * drive/controller combinations */
1943*4882a593Smuzhiyun
1944*4882a593Smuzhiyun #ifdef fd_chose_dma_mode
1945*4882a593Smuzhiyun if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) {
1946*4882a593Smuzhiyun unsigned long flags = claim_dma_lock();
1947*4882a593Smuzhiyun fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length);
1948*4882a593Smuzhiyun release_dma_lock(flags);
1949*4882a593Smuzhiyun }
1950*4882a593Smuzhiyun #endif
1951*4882a593Smuzhiyun
1952*4882a593Smuzhiyun if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
1953*4882a593Smuzhiyun perpendicular_mode(current_fdc);
1954*4882a593Smuzhiyun fdc_specify(current_fdc, current_drive); /* must be done here because of hut, hlt ... */
1955*4882a593Smuzhiyun seek_floppy();
1956*4882a593Smuzhiyun } else {
1957*4882a593Smuzhiyun if ((raw_cmd->flags & FD_RAW_READ) ||
1958*4882a593Smuzhiyun (raw_cmd->flags & FD_RAW_WRITE))
1959*4882a593Smuzhiyun fdc_specify(current_fdc, current_drive);
1960*4882a593Smuzhiyun setup_rw_floppy();
1961*4882a593Smuzhiyun }
1962*4882a593Smuzhiyun }
1963*4882a593Smuzhiyun
floppy_start(void)1964*4882a593Smuzhiyun static void floppy_start(void)
1965*4882a593Smuzhiyun {
1966*4882a593Smuzhiyun reschedule_timeout(current_drive, "floppy start");
1967*4882a593Smuzhiyun
1968*4882a593Smuzhiyun scandrives();
1969*4882a593Smuzhiyun debug_dcl(drive_params[current_drive].flags,
1970*4882a593Smuzhiyun "setting NEWCHANGE in floppy_start\n");
1971*4882a593Smuzhiyun set_bit(FD_DISK_NEWCHANGE_BIT, &drive_state[current_drive].flags);
1972*4882a593Smuzhiyun floppy_ready();
1973*4882a593Smuzhiyun }
1974*4882a593Smuzhiyun
1975*4882a593Smuzhiyun /*
1976*4882a593Smuzhiyun * ========================================================================
1977*4882a593Smuzhiyun * here ends the bottom half. Exported routines are:
1978*4882a593Smuzhiyun * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc,
1979*4882a593Smuzhiyun * start_motor, reset_fdc, reset_fdc_info, interpret_errors.
1980*4882a593Smuzhiyun * Initialization also uses output_byte, result, set_dor, floppy_interrupt
1981*4882a593Smuzhiyun * and set_dor.
1982*4882a593Smuzhiyun * ========================================================================
1983*4882a593Smuzhiyun */
1984*4882a593Smuzhiyun /*
1985*4882a593Smuzhiyun * General purpose continuations.
1986*4882a593Smuzhiyun * ==============================
1987*4882a593Smuzhiyun */
1988*4882a593Smuzhiyun
do_wakeup(void)1989*4882a593Smuzhiyun static void do_wakeup(void)
1990*4882a593Smuzhiyun {
1991*4882a593Smuzhiyun reschedule_timeout(MAXTIMEOUT, "do wakeup");
1992*4882a593Smuzhiyun cont = NULL;
1993*4882a593Smuzhiyun command_status += 2;
1994*4882a593Smuzhiyun wake_up(&command_done);
1995*4882a593Smuzhiyun }
1996*4882a593Smuzhiyun
1997*4882a593Smuzhiyun static const struct cont_t wakeup_cont = {
1998*4882a593Smuzhiyun .interrupt = empty,
1999*4882a593Smuzhiyun .redo = do_wakeup,
2000*4882a593Smuzhiyun .error = empty,
2001*4882a593Smuzhiyun .done = (done_f)empty
2002*4882a593Smuzhiyun };
2003*4882a593Smuzhiyun
2004*4882a593Smuzhiyun static const struct cont_t intr_cont = {
2005*4882a593Smuzhiyun .interrupt = empty,
2006*4882a593Smuzhiyun .redo = process_fd_request,
2007*4882a593Smuzhiyun .error = empty,
2008*4882a593Smuzhiyun .done = (done_f)empty
2009*4882a593Smuzhiyun };
2010*4882a593Smuzhiyun
2011*4882a593Smuzhiyun /* schedules handler, waiting for completion. May be interrupted, will then
2012*4882a593Smuzhiyun * return -EINTR, in which case the driver will automatically be unlocked.
2013*4882a593Smuzhiyun */
wait_til_done(void (* handler)(void),bool interruptible)2014*4882a593Smuzhiyun static int wait_til_done(void (*handler)(void), bool interruptible)
2015*4882a593Smuzhiyun {
2016*4882a593Smuzhiyun int ret;
2017*4882a593Smuzhiyun
2018*4882a593Smuzhiyun schedule_bh(handler);
2019*4882a593Smuzhiyun
2020*4882a593Smuzhiyun if (interruptible)
2021*4882a593Smuzhiyun wait_event_interruptible(command_done, command_status >= 2);
2022*4882a593Smuzhiyun else
2023*4882a593Smuzhiyun wait_event(command_done, command_status >= 2);
2024*4882a593Smuzhiyun
2025*4882a593Smuzhiyun if (command_status < 2) {
2026*4882a593Smuzhiyun cancel_activity();
2027*4882a593Smuzhiyun cont = &intr_cont;
2028*4882a593Smuzhiyun reset_fdc();
2029*4882a593Smuzhiyun return -EINTR;
2030*4882a593Smuzhiyun }
2031*4882a593Smuzhiyun
2032*4882a593Smuzhiyun if (fdc_state[current_fdc].reset)
2033*4882a593Smuzhiyun command_status = FD_COMMAND_ERROR;
2034*4882a593Smuzhiyun if (command_status == FD_COMMAND_OKAY)
2035*4882a593Smuzhiyun ret = 0;
2036*4882a593Smuzhiyun else
2037*4882a593Smuzhiyun ret = -EIO;
2038*4882a593Smuzhiyun command_status = FD_COMMAND_NONE;
2039*4882a593Smuzhiyun return ret;
2040*4882a593Smuzhiyun }
2041*4882a593Smuzhiyun
generic_done(int result)2042*4882a593Smuzhiyun static void generic_done(int result)
2043*4882a593Smuzhiyun {
2044*4882a593Smuzhiyun command_status = result;
2045*4882a593Smuzhiyun cont = &wakeup_cont;
2046*4882a593Smuzhiyun }
2047*4882a593Smuzhiyun
generic_success(void)2048*4882a593Smuzhiyun static void generic_success(void)
2049*4882a593Smuzhiyun {
2050*4882a593Smuzhiyun cont->done(1);
2051*4882a593Smuzhiyun }
2052*4882a593Smuzhiyun
generic_failure(void)2053*4882a593Smuzhiyun static void generic_failure(void)
2054*4882a593Smuzhiyun {
2055*4882a593Smuzhiyun cont->done(0);
2056*4882a593Smuzhiyun }
2057*4882a593Smuzhiyun
success_and_wakeup(void)2058*4882a593Smuzhiyun static void success_and_wakeup(void)
2059*4882a593Smuzhiyun {
2060*4882a593Smuzhiyun generic_success();
2061*4882a593Smuzhiyun cont->redo();
2062*4882a593Smuzhiyun }
2063*4882a593Smuzhiyun
2064*4882a593Smuzhiyun /*
2065*4882a593Smuzhiyun * formatting and rw support.
2066*4882a593Smuzhiyun * ==========================
2067*4882a593Smuzhiyun */
2068*4882a593Smuzhiyun
next_valid_format(int drive)2069*4882a593Smuzhiyun static int next_valid_format(int drive)
2070*4882a593Smuzhiyun {
2071*4882a593Smuzhiyun int probed_format;
2072*4882a593Smuzhiyun
2073*4882a593Smuzhiyun probed_format = drive_state[drive].probed_format;
2074*4882a593Smuzhiyun while (1) {
2075*4882a593Smuzhiyun if (probed_format >= FD_AUTODETECT_SIZE ||
2076*4882a593Smuzhiyun !drive_params[drive].autodetect[probed_format]) {
2077*4882a593Smuzhiyun drive_state[drive].probed_format = 0;
2078*4882a593Smuzhiyun return 1;
2079*4882a593Smuzhiyun }
2080*4882a593Smuzhiyun if (floppy_type[drive_params[drive].autodetect[probed_format]].sect) {
2081*4882a593Smuzhiyun drive_state[drive].probed_format = probed_format;
2082*4882a593Smuzhiyun return 0;
2083*4882a593Smuzhiyun }
2084*4882a593Smuzhiyun probed_format++;
2085*4882a593Smuzhiyun }
2086*4882a593Smuzhiyun }
2087*4882a593Smuzhiyun
bad_flp_intr(void)2088*4882a593Smuzhiyun static void bad_flp_intr(void)
2089*4882a593Smuzhiyun {
2090*4882a593Smuzhiyun int err_count;
2091*4882a593Smuzhiyun
2092*4882a593Smuzhiyun if (probing) {
2093*4882a593Smuzhiyun drive_state[current_drive].probed_format++;
2094*4882a593Smuzhiyun if (!next_valid_format(current_drive))
2095*4882a593Smuzhiyun return;
2096*4882a593Smuzhiyun }
2097*4882a593Smuzhiyun err_count = ++floppy_errors;
2098*4882a593Smuzhiyun INFBOUND(write_errors[current_drive].badness, err_count);
2099*4882a593Smuzhiyun if (err_count > drive_params[current_drive].max_errors.abort)
2100*4882a593Smuzhiyun cont->done(0);
2101*4882a593Smuzhiyun if (err_count > drive_params[current_drive].max_errors.reset)
2102*4882a593Smuzhiyun fdc_state[current_fdc].reset = 1;
2103*4882a593Smuzhiyun else if (err_count > drive_params[current_drive].max_errors.recal)
2104*4882a593Smuzhiyun drive_state[current_drive].track = NEED_2_RECAL;
2105*4882a593Smuzhiyun }
2106*4882a593Smuzhiyun
set_floppy(int drive)2107*4882a593Smuzhiyun static void set_floppy(int drive)
2108*4882a593Smuzhiyun {
2109*4882a593Smuzhiyun int type = ITYPE(drive_state[drive].fd_device);
2110*4882a593Smuzhiyun
2111*4882a593Smuzhiyun if (type)
2112*4882a593Smuzhiyun _floppy = floppy_type + type;
2113*4882a593Smuzhiyun else
2114*4882a593Smuzhiyun _floppy = current_type[drive];
2115*4882a593Smuzhiyun }
2116*4882a593Smuzhiyun
2117*4882a593Smuzhiyun /*
2118*4882a593Smuzhiyun * formatting support.
2119*4882a593Smuzhiyun * ===================
2120*4882a593Smuzhiyun */
format_interrupt(void)2121*4882a593Smuzhiyun static void format_interrupt(void)
2122*4882a593Smuzhiyun {
2123*4882a593Smuzhiyun switch (interpret_errors()) {
2124*4882a593Smuzhiyun case 1:
2125*4882a593Smuzhiyun cont->error();
2126*4882a593Smuzhiyun case 2:
2127*4882a593Smuzhiyun break;
2128*4882a593Smuzhiyun case 0:
2129*4882a593Smuzhiyun cont->done(1);
2130*4882a593Smuzhiyun }
2131*4882a593Smuzhiyun cont->redo();
2132*4882a593Smuzhiyun }
2133*4882a593Smuzhiyun
2134*4882a593Smuzhiyun #define FM_MODE(x, y) ((y) & ~(((x)->rate & 0x80) >> 1))
2135*4882a593Smuzhiyun #define CT(x) ((x) | 0xc0)
2136*4882a593Smuzhiyun
setup_format_params(int track)2137*4882a593Smuzhiyun static void setup_format_params(int track)
2138*4882a593Smuzhiyun {
2139*4882a593Smuzhiyun int n;
2140*4882a593Smuzhiyun int il;
2141*4882a593Smuzhiyun int count;
2142*4882a593Smuzhiyun int head_shift;
2143*4882a593Smuzhiyun int track_shift;
2144*4882a593Smuzhiyun struct fparm {
2145*4882a593Smuzhiyun unsigned char track, head, sect, size;
2146*4882a593Smuzhiyun } *here = (struct fparm *)floppy_track_buffer;
2147*4882a593Smuzhiyun
2148*4882a593Smuzhiyun raw_cmd = &default_raw_cmd;
2149*4882a593Smuzhiyun raw_cmd->track = track;
2150*4882a593Smuzhiyun
2151*4882a593Smuzhiyun raw_cmd->flags = (FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN |
2152*4882a593Smuzhiyun FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
2153*4882a593Smuzhiyun raw_cmd->rate = _floppy->rate & 0x43;
2154*4882a593Smuzhiyun raw_cmd->cmd_count = NR_F;
2155*4882a593Smuzhiyun raw_cmd->cmd[COMMAND] = FM_MODE(_floppy, FD_FORMAT);
2156*4882a593Smuzhiyun raw_cmd->cmd[DR_SELECT] = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
2157*4882a593Smuzhiyun raw_cmd->cmd[F_SIZECODE] = FD_SIZECODE(_floppy);
2158*4882a593Smuzhiyun raw_cmd->cmd[F_SECT_PER_TRACK] = _floppy->sect << 2 >> raw_cmd->cmd[F_SIZECODE];
2159*4882a593Smuzhiyun raw_cmd->cmd[F_GAP] = _floppy->fmt_gap;
2160*4882a593Smuzhiyun raw_cmd->cmd[F_FILL] = FD_FILL_BYTE;
2161*4882a593Smuzhiyun
2162*4882a593Smuzhiyun raw_cmd->kernel_data = floppy_track_buffer;
2163*4882a593Smuzhiyun raw_cmd->length = 4 * raw_cmd->cmd[F_SECT_PER_TRACK];
2164*4882a593Smuzhiyun
2165*4882a593Smuzhiyun if (!raw_cmd->cmd[F_SECT_PER_TRACK])
2166*4882a593Smuzhiyun return;
2167*4882a593Smuzhiyun
2168*4882a593Smuzhiyun /* allow for about 30ms for data transport per track */
2169*4882a593Smuzhiyun head_shift = (raw_cmd->cmd[F_SECT_PER_TRACK] + 5) / 6;
2170*4882a593Smuzhiyun
2171*4882a593Smuzhiyun /* a ``cylinder'' is two tracks plus a little stepping time */
2172*4882a593Smuzhiyun track_shift = 2 * head_shift + 3;
2173*4882a593Smuzhiyun
2174*4882a593Smuzhiyun /* position of logical sector 1 on this track */
2175*4882a593Smuzhiyun n = (track_shift * format_req.track + head_shift * format_req.head)
2176*4882a593Smuzhiyun % raw_cmd->cmd[F_SECT_PER_TRACK];
2177*4882a593Smuzhiyun
2178*4882a593Smuzhiyun /* determine interleave */
2179*4882a593Smuzhiyun il = 1;
2180*4882a593Smuzhiyun if (_floppy->fmt_gap < 0x22)
2181*4882a593Smuzhiyun il++;
2182*4882a593Smuzhiyun
2183*4882a593Smuzhiyun /* initialize field */
2184*4882a593Smuzhiyun for (count = 0; count < raw_cmd->cmd[F_SECT_PER_TRACK]; ++count) {
2185*4882a593Smuzhiyun here[count].track = format_req.track;
2186*4882a593Smuzhiyun here[count].head = format_req.head;
2187*4882a593Smuzhiyun here[count].sect = 0;
2188*4882a593Smuzhiyun here[count].size = raw_cmd->cmd[F_SIZECODE];
2189*4882a593Smuzhiyun }
2190*4882a593Smuzhiyun /* place logical sectors */
2191*4882a593Smuzhiyun for (count = 1; count <= raw_cmd->cmd[F_SECT_PER_TRACK]; ++count) {
2192*4882a593Smuzhiyun here[n].sect = count;
2193*4882a593Smuzhiyun n = (n + il) % raw_cmd->cmd[F_SECT_PER_TRACK];
2194*4882a593Smuzhiyun if (here[n].sect) { /* sector busy, find next free sector */
2195*4882a593Smuzhiyun ++n;
2196*4882a593Smuzhiyun if (n >= raw_cmd->cmd[F_SECT_PER_TRACK]) {
2197*4882a593Smuzhiyun n -= raw_cmd->cmd[F_SECT_PER_TRACK];
2198*4882a593Smuzhiyun while (here[n].sect)
2199*4882a593Smuzhiyun ++n;
2200*4882a593Smuzhiyun }
2201*4882a593Smuzhiyun }
2202*4882a593Smuzhiyun }
2203*4882a593Smuzhiyun if (_floppy->stretch & FD_SECTBASEMASK) {
2204*4882a593Smuzhiyun for (count = 0; count < raw_cmd->cmd[F_SECT_PER_TRACK]; count++)
2205*4882a593Smuzhiyun here[count].sect += FD_SECTBASE(_floppy) - 1;
2206*4882a593Smuzhiyun }
2207*4882a593Smuzhiyun }
2208*4882a593Smuzhiyun
redo_format(void)2209*4882a593Smuzhiyun static void redo_format(void)
2210*4882a593Smuzhiyun {
2211*4882a593Smuzhiyun buffer_track = -1;
2212*4882a593Smuzhiyun setup_format_params(format_req.track << STRETCH(_floppy));
2213*4882a593Smuzhiyun floppy_start();
2214*4882a593Smuzhiyun debugt(__func__, "queue format request");
2215*4882a593Smuzhiyun }
2216*4882a593Smuzhiyun
2217*4882a593Smuzhiyun static const struct cont_t format_cont = {
2218*4882a593Smuzhiyun .interrupt = format_interrupt,
2219*4882a593Smuzhiyun .redo = redo_format,
2220*4882a593Smuzhiyun .error = bad_flp_intr,
2221*4882a593Smuzhiyun .done = generic_done
2222*4882a593Smuzhiyun };
2223*4882a593Smuzhiyun
do_format(int drive,struct format_descr * tmp_format_req)2224*4882a593Smuzhiyun static int do_format(int drive, struct format_descr *tmp_format_req)
2225*4882a593Smuzhiyun {
2226*4882a593Smuzhiyun int ret;
2227*4882a593Smuzhiyun
2228*4882a593Smuzhiyun if (lock_fdc(drive))
2229*4882a593Smuzhiyun return -EINTR;
2230*4882a593Smuzhiyun
2231*4882a593Smuzhiyun set_floppy(drive);
2232*4882a593Smuzhiyun if (!_floppy ||
2233*4882a593Smuzhiyun _floppy->track > drive_params[current_drive].tracks ||
2234*4882a593Smuzhiyun tmp_format_req->track >= _floppy->track ||
2235*4882a593Smuzhiyun tmp_format_req->head >= _floppy->head ||
2236*4882a593Smuzhiyun (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
2237*4882a593Smuzhiyun !_floppy->fmt_gap) {
2238*4882a593Smuzhiyun process_fd_request();
2239*4882a593Smuzhiyun return -EINVAL;
2240*4882a593Smuzhiyun }
2241*4882a593Smuzhiyun format_req = *tmp_format_req;
2242*4882a593Smuzhiyun cont = &format_cont;
2243*4882a593Smuzhiyun floppy_errors = 0;
2244*4882a593Smuzhiyun ret = wait_til_done(redo_format, true);
2245*4882a593Smuzhiyun if (ret == -EINTR)
2246*4882a593Smuzhiyun return -EINTR;
2247*4882a593Smuzhiyun process_fd_request();
2248*4882a593Smuzhiyun return ret;
2249*4882a593Smuzhiyun }
2250*4882a593Smuzhiyun
2251*4882a593Smuzhiyun /*
2252*4882a593Smuzhiyun * Buffer read/write and support
2253*4882a593Smuzhiyun * =============================
2254*4882a593Smuzhiyun */
2255*4882a593Smuzhiyun
floppy_end_request(struct request * req,blk_status_t error)2256*4882a593Smuzhiyun static void floppy_end_request(struct request *req, blk_status_t error)
2257*4882a593Smuzhiyun {
2258*4882a593Smuzhiyun unsigned int nr_sectors = current_count_sectors;
2259*4882a593Smuzhiyun unsigned int drive = (unsigned long)req->rq_disk->private_data;
2260*4882a593Smuzhiyun
2261*4882a593Smuzhiyun /* current_count_sectors can be zero if transfer failed */
2262*4882a593Smuzhiyun if (error)
2263*4882a593Smuzhiyun nr_sectors = blk_rq_cur_sectors(req);
2264*4882a593Smuzhiyun if (blk_update_request(req, error, nr_sectors << 9))
2265*4882a593Smuzhiyun return;
2266*4882a593Smuzhiyun __blk_mq_end_request(req, error);
2267*4882a593Smuzhiyun
2268*4882a593Smuzhiyun /* We're done with the request */
2269*4882a593Smuzhiyun floppy_off(drive);
2270*4882a593Smuzhiyun current_req = NULL;
2271*4882a593Smuzhiyun }
2272*4882a593Smuzhiyun
2273*4882a593Smuzhiyun /* new request_done. Can handle physical sectors which are smaller than a
2274*4882a593Smuzhiyun * logical buffer */
request_done(int uptodate)2275*4882a593Smuzhiyun static void request_done(int uptodate)
2276*4882a593Smuzhiyun {
2277*4882a593Smuzhiyun struct request *req = current_req;
2278*4882a593Smuzhiyun int block;
2279*4882a593Smuzhiyun char msg[sizeof("request done ") + sizeof(int) * 3];
2280*4882a593Smuzhiyun
2281*4882a593Smuzhiyun probing = 0;
2282*4882a593Smuzhiyun snprintf(msg, sizeof(msg), "request done %d", uptodate);
2283*4882a593Smuzhiyun reschedule_timeout(MAXTIMEOUT, msg);
2284*4882a593Smuzhiyun
2285*4882a593Smuzhiyun if (!req) {
2286*4882a593Smuzhiyun pr_info("floppy.c: no request in request_done\n");
2287*4882a593Smuzhiyun return;
2288*4882a593Smuzhiyun }
2289*4882a593Smuzhiyun
2290*4882a593Smuzhiyun if (uptodate) {
2291*4882a593Smuzhiyun /* maintain values for invalidation on geometry
2292*4882a593Smuzhiyun * change */
2293*4882a593Smuzhiyun block = current_count_sectors + blk_rq_pos(req);
2294*4882a593Smuzhiyun INFBOUND(drive_state[current_drive].maxblock, block);
2295*4882a593Smuzhiyun if (block > _floppy->sect)
2296*4882a593Smuzhiyun drive_state[current_drive].maxtrack = 1;
2297*4882a593Smuzhiyun
2298*4882a593Smuzhiyun floppy_end_request(req, 0);
2299*4882a593Smuzhiyun } else {
2300*4882a593Smuzhiyun if (rq_data_dir(req) == WRITE) {
2301*4882a593Smuzhiyun /* record write error information */
2302*4882a593Smuzhiyun write_errors[current_drive].write_errors++;
2303*4882a593Smuzhiyun if (write_errors[current_drive].write_errors == 1) {
2304*4882a593Smuzhiyun write_errors[current_drive].first_error_sector = blk_rq_pos(req);
2305*4882a593Smuzhiyun write_errors[current_drive].first_error_generation = drive_state[current_drive].generation;
2306*4882a593Smuzhiyun }
2307*4882a593Smuzhiyun write_errors[current_drive].last_error_sector = blk_rq_pos(req);
2308*4882a593Smuzhiyun write_errors[current_drive].last_error_generation = drive_state[current_drive].generation;
2309*4882a593Smuzhiyun }
2310*4882a593Smuzhiyun floppy_end_request(req, BLK_STS_IOERR);
2311*4882a593Smuzhiyun }
2312*4882a593Smuzhiyun }
2313*4882a593Smuzhiyun
2314*4882a593Smuzhiyun /* Interrupt handler evaluating the result of the r/w operation */
rw_interrupt(void)2315*4882a593Smuzhiyun static void rw_interrupt(void)
2316*4882a593Smuzhiyun {
2317*4882a593Smuzhiyun int eoc;
2318*4882a593Smuzhiyun int ssize;
2319*4882a593Smuzhiyun int heads;
2320*4882a593Smuzhiyun int nr_sectors;
2321*4882a593Smuzhiyun
2322*4882a593Smuzhiyun if (reply_buffer[R_HEAD] >= 2) {
2323*4882a593Smuzhiyun /* some Toshiba floppy controllers occasionnally seem to
2324*4882a593Smuzhiyun * return bogus interrupts after read/write operations, which
2325*4882a593Smuzhiyun * can be recognized by a bad head number (>= 2) */
2326*4882a593Smuzhiyun return;
2327*4882a593Smuzhiyun }
2328*4882a593Smuzhiyun
2329*4882a593Smuzhiyun if (!drive_state[current_drive].first_read_date)
2330*4882a593Smuzhiyun drive_state[current_drive].first_read_date = jiffies;
2331*4882a593Smuzhiyun
2332*4882a593Smuzhiyun nr_sectors = 0;
2333*4882a593Smuzhiyun ssize = DIV_ROUND_UP(1 << raw_cmd->cmd[SIZECODE], 4);
2334*4882a593Smuzhiyun
2335*4882a593Smuzhiyun if (reply_buffer[ST1] & ST1_EOC)
2336*4882a593Smuzhiyun eoc = 1;
2337*4882a593Smuzhiyun else
2338*4882a593Smuzhiyun eoc = 0;
2339*4882a593Smuzhiyun
2340*4882a593Smuzhiyun if (raw_cmd->cmd[COMMAND] & 0x80)
2341*4882a593Smuzhiyun heads = 2;
2342*4882a593Smuzhiyun else
2343*4882a593Smuzhiyun heads = 1;
2344*4882a593Smuzhiyun
2345*4882a593Smuzhiyun nr_sectors = (((reply_buffer[R_TRACK] - raw_cmd->cmd[TRACK]) * heads +
2346*4882a593Smuzhiyun reply_buffer[R_HEAD] - raw_cmd->cmd[HEAD]) * raw_cmd->cmd[SECT_PER_TRACK] +
2347*4882a593Smuzhiyun reply_buffer[R_SECTOR] - raw_cmd->cmd[SECTOR] + eoc) << raw_cmd->cmd[SIZECODE] >> 2;
2348*4882a593Smuzhiyun
2349*4882a593Smuzhiyun if (nr_sectors / ssize >
2350*4882a593Smuzhiyun DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
2351*4882a593Smuzhiyun DPRINT("long rw: %x instead of %lx\n",
2352*4882a593Smuzhiyun nr_sectors, current_count_sectors);
2353*4882a593Smuzhiyun pr_info("rs=%d s=%d\n", reply_buffer[R_SECTOR],
2354*4882a593Smuzhiyun raw_cmd->cmd[SECTOR]);
2355*4882a593Smuzhiyun pr_info("rh=%d h=%d\n", reply_buffer[R_HEAD],
2356*4882a593Smuzhiyun raw_cmd->cmd[HEAD]);
2357*4882a593Smuzhiyun pr_info("rt=%d t=%d\n", reply_buffer[R_TRACK],
2358*4882a593Smuzhiyun raw_cmd->cmd[TRACK]);
2359*4882a593Smuzhiyun pr_info("heads=%d eoc=%d\n", heads, eoc);
2360*4882a593Smuzhiyun pr_info("spt=%d st=%d ss=%d\n",
2361*4882a593Smuzhiyun raw_cmd->cmd[SECT_PER_TRACK], fsector_t, ssize);
2362*4882a593Smuzhiyun pr_info("in_sector_offset=%d\n", in_sector_offset);
2363*4882a593Smuzhiyun }
2364*4882a593Smuzhiyun
2365*4882a593Smuzhiyun nr_sectors -= in_sector_offset;
2366*4882a593Smuzhiyun INFBOUND(nr_sectors, 0);
2367*4882a593Smuzhiyun SUPBOUND(current_count_sectors, nr_sectors);
2368*4882a593Smuzhiyun
2369*4882a593Smuzhiyun switch (interpret_errors()) {
2370*4882a593Smuzhiyun case 2:
2371*4882a593Smuzhiyun cont->redo();
2372*4882a593Smuzhiyun return;
2373*4882a593Smuzhiyun case 1:
2374*4882a593Smuzhiyun if (!current_count_sectors) {
2375*4882a593Smuzhiyun cont->error();
2376*4882a593Smuzhiyun cont->redo();
2377*4882a593Smuzhiyun return;
2378*4882a593Smuzhiyun }
2379*4882a593Smuzhiyun break;
2380*4882a593Smuzhiyun case 0:
2381*4882a593Smuzhiyun if (!current_count_sectors) {
2382*4882a593Smuzhiyun cont->redo();
2383*4882a593Smuzhiyun return;
2384*4882a593Smuzhiyun }
2385*4882a593Smuzhiyun current_type[current_drive] = _floppy;
2386*4882a593Smuzhiyun floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2387*4882a593Smuzhiyun break;
2388*4882a593Smuzhiyun }
2389*4882a593Smuzhiyun
2390*4882a593Smuzhiyun if (probing) {
2391*4882a593Smuzhiyun if (drive_params[current_drive].flags & FTD_MSG)
2392*4882a593Smuzhiyun DPRINT("Auto-detected floppy type %s in fd%d\n",
2393*4882a593Smuzhiyun _floppy->name, current_drive);
2394*4882a593Smuzhiyun current_type[current_drive] = _floppy;
2395*4882a593Smuzhiyun floppy_sizes[TOMINOR(current_drive)] = _floppy->size;
2396*4882a593Smuzhiyun probing = 0;
2397*4882a593Smuzhiyun }
2398*4882a593Smuzhiyun
2399*4882a593Smuzhiyun if (CT(raw_cmd->cmd[COMMAND]) != FD_READ ||
2400*4882a593Smuzhiyun raw_cmd->kernel_data == bio_data(current_req->bio)) {
2401*4882a593Smuzhiyun /* transfer directly from buffer */
2402*4882a593Smuzhiyun cont->done(1);
2403*4882a593Smuzhiyun } else if (CT(raw_cmd->cmd[COMMAND]) == FD_READ) {
2404*4882a593Smuzhiyun buffer_track = raw_cmd->track;
2405*4882a593Smuzhiyun buffer_drive = current_drive;
2406*4882a593Smuzhiyun INFBOUND(buffer_max, nr_sectors + fsector_t);
2407*4882a593Smuzhiyun }
2408*4882a593Smuzhiyun cont->redo();
2409*4882a593Smuzhiyun }
2410*4882a593Smuzhiyun
2411*4882a593Smuzhiyun /* Compute maximal contiguous buffer size. */
buffer_chain_size(void)2412*4882a593Smuzhiyun static int buffer_chain_size(void)
2413*4882a593Smuzhiyun {
2414*4882a593Smuzhiyun struct bio_vec bv;
2415*4882a593Smuzhiyun int size;
2416*4882a593Smuzhiyun struct req_iterator iter;
2417*4882a593Smuzhiyun char *base;
2418*4882a593Smuzhiyun
2419*4882a593Smuzhiyun base = bio_data(current_req->bio);
2420*4882a593Smuzhiyun size = 0;
2421*4882a593Smuzhiyun
2422*4882a593Smuzhiyun rq_for_each_segment(bv, current_req, iter) {
2423*4882a593Smuzhiyun if (page_address(bv.bv_page) + bv.bv_offset != base + size)
2424*4882a593Smuzhiyun break;
2425*4882a593Smuzhiyun
2426*4882a593Smuzhiyun size += bv.bv_len;
2427*4882a593Smuzhiyun }
2428*4882a593Smuzhiyun
2429*4882a593Smuzhiyun return size >> 9;
2430*4882a593Smuzhiyun }
2431*4882a593Smuzhiyun
2432*4882a593Smuzhiyun /* Compute the maximal transfer size */
transfer_size(int ssize,int max_sector,int max_size)2433*4882a593Smuzhiyun static int transfer_size(int ssize, int max_sector, int max_size)
2434*4882a593Smuzhiyun {
2435*4882a593Smuzhiyun SUPBOUND(max_sector, fsector_t + max_size);
2436*4882a593Smuzhiyun
2437*4882a593Smuzhiyun /* alignment */
2438*4882a593Smuzhiyun max_sector -= (max_sector % _floppy->sect) % ssize;
2439*4882a593Smuzhiyun
2440*4882a593Smuzhiyun /* transfer size, beginning not aligned */
2441*4882a593Smuzhiyun current_count_sectors = max_sector - fsector_t;
2442*4882a593Smuzhiyun
2443*4882a593Smuzhiyun return max_sector;
2444*4882a593Smuzhiyun }
2445*4882a593Smuzhiyun
2446*4882a593Smuzhiyun /*
2447*4882a593Smuzhiyun * Move data from/to the track buffer to/from the buffer cache.
2448*4882a593Smuzhiyun */
copy_buffer(int ssize,int max_sector,int max_sector_2)2449*4882a593Smuzhiyun static void copy_buffer(int ssize, int max_sector, int max_sector_2)
2450*4882a593Smuzhiyun {
2451*4882a593Smuzhiyun int remaining; /* number of transferred 512-byte sectors */
2452*4882a593Smuzhiyun struct bio_vec bv;
2453*4882a593Smuzhiyun char *buffer;
2454*4882a593Smuzhiyun char *dma_buffer;
2455*4882a593Smuzhiyun int size;
2456*4882a593Smuzhiyun struct req_iterator iter;
2457*4882a593Smuzhiyun
2458*4882a593Smuzhiyun max_sector = transfer_size(ssize,
2459*4882a593Smuzhiyun min(max_sector, max_sector_2),
2460*4882a593Smuzhiyun blk_rq_sectors(current_req));
2461*4882a593Smuzhiyun
2462*4882a593Smuzhiyun if (current_count_sectors <= 0 && CT(raw_cmd->cmd[COMMAND]) == FD_WRITE &&
2463*4882a593Smuzhiyun buffer_max > fsector_t + blk_rq_sectors(current_req))
2464*4882a593Smuzhiyun current_count_sectors = min_t(int, buffer_max - fsector_t,
2465*4882a593Smuzhiyun blk_rq_sectors(current_req));
2466*4882a593Smuzhiyun
2467*4882a593Smuzhiyun remaining = current_count_sectors << 9;
2468*4882a593Smuzhiyun if (remaining > blk_rq_bytes(current_req) && CT(raw_cmd->cmd[COMMAND]) == FD_WRITE) {
2469*4882a593Smuzhiyun DPRINT("in copy buffer\n");
2470*4882a593Smuzhiyun pr_info("current_count_sectors=%ld\n", current_count_sectors);
2471*4882a593Smuzhiyun pr_info("remaining=%d\n", remaining >> 9);
2472*4882a593Smuzhiyun pr_info("current_req->nr_sectors=%u\n",
2473*4882a593Smuzhiyun blk_rq_sectors(current_req));
2474*4882a593Smuzhiyun pr_info("current_req->current_nr_sectors=%u\n",
2475*4882a593Smuzhiyun blk_rq_cur_sectors(current_req));
2476*4882a593Smuzhiyun pr_info("max_sector=%d\n", max_sector);
2477*4882a593Smuzhiyun pr_info("ssize=%d\n", ssize);
2478*4882a593Smuzhiyun }
2479*4882a593Smuzhiyun
2480*4882a593Smuzhiyun buffer_max = max(max_sector, buffer_max);
2481*4882a593Smuzhiyun
2482*4882a593Smuzhiyun dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
2483*4882a593Smuzhiyun
2484*4882a593Smuzhiyun size = blk_rq_cur_bytes(current_req);
2485*4882a593Smuzhiyun
2486*4882a593Smuzhiyun rq_for_each_segment(bv, current_req, iter) {
2487*4882a593Smuzhiyun if (!remaining)
2488*4882a593Smuzhiyun break;
2489*4882a593Smuzhiyun
2490*4882a593Smuzhiyun size = bv.bv_len;
2491*4882a593Smuzhiyun SUPBOUND(size, remaining);
2492*4882a593Smuzhiyun
2493*4882a593Smuzhiyun buffer = page_address(bv.bv_page) + bv.bv_offset;
2494*4882a593Smuzhiyun if (dma_buffer + size >
2495*4882a593Smuzhiyun floppy_track_buffer + (max_buffer_sectors << 10) ||
2496*4882a593Smuzhiyun dma_buffer < floppy_track_buffer) {
2497*4882a593Smuzhiyun DPRINT("buffer overrun in copy buffer %d\n",
2498*4882a593Smuzhiyun (int)((floppy_track_buffer - dma_buffer) >> 9));
2499*4882a593Smuzhiyun pr_info("fsector_t=%d buffer_min=%d\n",
2500*4882a593Smuzhiyun fsector_t, buffer_min);
2501*4882a593Smuzhiyun pr_info("current_count_sectors=%ld\n",
2502*4882a593Smuzhiyun current_count_sectors);
2503*4882a593Smuzhiyun if (CT(raw_cmd->cmd[COMMAND]) == FD_READ)
2504*4882a593Smuzhiyun pr_info("read\n");
2505*4882a593Smuzhiyun if (CT(raw_cmd->cmd[COMMAND]) == FD_WRITE)
2506*4882a593Smuzhiyun pr_info("write\n");
2507*4882a593Smuzhiyun break;
2508*4882a593Smuzhiyun }
2509*4882a593Smuzhiyun if (((unsigned long)buffer) % 512)
2510*4882a593Smuzhiyun DPRINT("%p buffer not aligned\n", buffer);
2511*4882a593Smuzhiyun
2512*4882a593Smuzhiyun if (CT(raw_cmd->cmd[COMMAND]) == FD_READ)
2513*4882a593Smuzhiyun memcpy(buffer, dma_buffer, size);
2514*4882a593Smuzhiyun else
2515*4882a593Smuzhiyun memcpy(dma_buffer, buffer, size);
2516*4882a593Smuzhiyun
2517*4882a593Smuzhiyun remaining -= size;
2518*4882a593Smuzhiyun dma_buffer += size;
2519*4882a593Smuzhiyun }
2520*4882a593Smuzhiyun if (remaining) {
2521*4882a593Smuzhiyun if (remaining > 0)
2522*4882a593Smuzhiyun max_sector -= remaining >> 9;
2523*4882a593Smuzhiyun DPRINT("weirdness: remaining %d\n", remaining >> 9);
2524*4882a593Smuzhiyun }
2525*4882a593Smuzhiyun }
2526*4882a593Smuzhiyun
2527*4882a593Smuzhiyun /* work around a bug in pseudo DMA
2528*4882a593Smuzhiyun * (on some FDCs) pseudo DMA does not stop when the CPU stops
2529*4882a593Smuzhiyun * sending data. Hence we need a different way to signal the
2530*4882a593Smuzhiyun * transfer length: We use raw_cmd->cmd[SECT_PER_TRACK]. Unfortunately, this
2531*4882a593Smuzhiyun * does not work with MT, hence we can only transfer one head at
2532*4882a593Smuzhiyun * a time
2533*4882a593Smuzhiyun */
virtualdmabug_workaround(void)2534*4882a593Smuzhiyun static void virtualdmabug_workaround(void)
2535*4882a593Smuzhiyun {
2536*4882a593Smuzhiyun int hard_sectors;
2537*4882a593Smuzhiyun int end_sector;
2538*4882a593Smuzhiyun
2539*4882a593Smuzhiyun if (CT(raw_cmd->cmd[COMMAND]) == FD_WRITE) {
2540*4882a593Smuzhiyun raw_cmd->cmd[COMMAND] &= ~0x80; /* switch off multiple track mode */
2541*4882a593Smuzhiyun
2542*4882a593Smuzhiyun hard_sectors = raw_cmd->length >> (7 + raw_cmd->cmd[SIZECODE]);
2543*4882a593Smuzhiyun end_sector = raw_cmd->cmd[SECTOR] + hard_sectors - 1;
2544*4882a593Smuzhiyun if (end_sector > raw_cmd->cmd[SECT_PER_TRACK]) {
2545*4882a593Smuzhiyun pr_info("too many sectors %d > %d\n",
2546*4882a593Smuzhiyun end_sector, raw_cmd->cmd[SECT_PER_TRACK]);
2547*4882a593Smuzhiyun return;
2548*4882a593Smuzhiyun }
2549*4882a593Smuzhiyun raw_cmd->cmd[SECT_PER_TRACK] = end_sector;
2550*4882a593Smuzhiyun /* make sure raw_cmd->cmd[SECT_PER_TRACK]
2551*4882a593Smuzhiyun * points to end of transfer */
2552*4882a593Smuzhiyun }
2553*4882a593Smuzhiyun }
2554*4882a593Smuzhiyun
2555*4882a593Smuzhiyun /*
2556*4882a593Smuzhiyun * Formulate a read/write request.
2557*4882a593Smuzhiyun * this routine decides where to load the data (directly to buffer, or to
2558*4882a593Smuzhiyun * tmp floppy area), how much data to load (the size of the buffer, the whole
2559*4882a593Smuzhiyun * track, or a single sector)
2560*4882a593Smuzhiyun * All floppy_track_buffer handling goes in here. If we ever add track buffer
2561*4882a593Smuzhiyun * allocation on the fly, it should be done here. No other part should need
2562*4882a593Smuzhiyun * modification.
2563*4882a593Smuzhiyun */
2564*4882a593Smuzhiyun
make_raw_rw_request(void)2565*4882a593Smuzhiyun static int make_raw_rw_request(void)
2566*4882a593Smuzhiyun {
2567*4882a593Smuzhiyun int aligned_sector_t;
2568*4882a593Smuzhiyun int max_sector;
2569*4882a593Smuzhiyun int max_size;
2570*4882a593Smuzhiyun int tracksize;
2571*4882a593Smuzhiyun int ssize;
2572*4882a593Smuzhiyun
2573*4882a593Smuzhiyun if (WARN(max_buffer_sectors == 0, "VFS: Block I/O scheduled on unopened device\n"))
2574*4882a593Smuzhiyun return 0;
2575*4882a593Smuzhiyun
2576*4882a593Smuzhiyun set_fdc((long)current_req->rq_disk->private_data);
2577*4882a593Smuzhiyun
2578*4882a593Smuzhiyun raw_cmd = &default_raw_cmd;
2579*4882a593Smuzhiyun raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK;
2580*4882a593Smuzhiyun raw_cmd->cmd_count = NR_RW;
2581*4882a593Smuzhiyun if (rq_data_dir(current_req) == READ) {
2582*4882a593Smuzhiyun raw_cmd->flags |= FD_RAW_READ;
2583*4882a593Smuzhiyun raw_cmd->cmd[COMMAND] = FM_MODE(_floppy, FD_READ);
2584*4882a593Smuzhiyun } else if (rq_data_dir(current_req) == WRITE) {
2585*4882a593Smuzhiyun raw_cmd->flags |= FD_RAW_WRITE;
2586*4882a593Smuzhiyun raw_cmd->cmd[COMMAND] = FM_MODE(_floppy, FD_WRITE);
2587*4882a593Smuzhiyun } else {
2588*4882a593Smuzhiyun DPRINT("%s: unknown command\n", __func__);
2589*4882a593Smuzhiyun return 0;
2590*4882a593Smuzhiyun }
2591*4882a593Smuzhiyun
2592*4882a593Smuzhiyun max_sector = _floppy->sect * _floppy->head;
2593*4882a593Smuzhiyun
2594*4882a593Smuzhiyun raw_cmd->cmd[TRACK] = (int)blk_rq_pos(current_req) / max_sector;
2595*4882a593Smuzhiyun fsector_t = (int)blk_rq_pos(current_req) % max_sector;
2596*4882a593Smuzhiyun if (_floppy->track && raw_cmd->cmd[TRACK] >= _floppy->track) {
2597*4882a593Smuzhiyun if (blk_rq_cur_sectors(current_req) & 1) {
2598*4882a593Smuzhiyun current_count_sectors = 1;
2599*4882a593Smuzhiyun return 1;
2600*4882a593Smuzhiyun } else
2601*4882a593Smuzhiyun return 0;
2602*4882a593Smuzhiyun }
2603*4882a593Smuzhiyun raw_cmd->cmd[HEAD] = fsector_t / _floppy->sect;
2604*4882a593Smuzhiyun
2605*4882a593Smuzhiyun if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
2606*4882a593Smuzhiyun test_bit(FD_NEED_TWADDLE_BIT, &drive_state[current_drive].flags)) &&
2607*4882a593Smuzhiyun fsector_t < _floppy->sect)
2608*4882a593Smuzhiyun max_sector = _floppy->sect;
2609*4882a593Smuzhiyun
2610*4882a593Smuzhiyun /* 2M disks have phantom sectors on the first track */
2611*4882a593Smuzhiyun if ((_floppy->rate & FD_2M) && (!raw_cmd->cmd[TRACK]) && (!raw_cmd->cmd[HEAD])) {
2612*4882a593Smuzhiyun max_sector = 2 * _floppy->sect / 3;
2613*4882a593Smuzhiyun if (fsector_t >= max_sector) {
2614*4882a593Smuzhiyun current_count_sectors =
2615*4882a593Smuzhiyun min_t(int, _floppy->sect - fsector_t,
2616*4882a593Smuzhiyun blk_rq_sectors(current_req));
2617*4882a593Smuzhiyun return 1;
2618*4882a593Smuzhiyun }
2619*4882a593Smuzhiyun raw_cmd->cmd[SIZECODE] = 2;
2620*4882a593Smuzhiyun } else
2621*4882a593Smuzhiyun raw_cmd->cmd[SIZECODE] = FD_SIZECODE(_floppy);
2622*4882a593Smuzhiyun raw_cmd->rate = _floppy->rate & 0x43;
2623*4882a593Smuzhiyun if ((_floppy->rate & FD_2M) &&
2624*4882a593Smuzhiyun (raw_cmd->cmd[TRACK] || raw_cmd->cmd[HEAD]) && raw_cmd->rate == 2)
2625*4882a593Smuzhiyun raw_cmd->rate = 1;
2626*4882a593Smuzhiyun
2627*4882a593Smuzhiyun if (raw_cmd->cmd[SIZECODE])
2628*4882a593Smuzhiyun raw_cmd->cmd[SIZECODE2] = 0xff;
2629*4882a593Smuzhiyun else
2630*4882a593Smuzhiyun raw_cmd->cmd[SIZECODE2] = 0x80;
2631*4882a593Smuzhiyun raw_cmd->track = raw_cmd->cmd[TRACK] << STRETCH(_floppy);
2632*4882a593Smuzhiyun raw_cmd->cmd[DR_SELECT] = UNIT(current_drive) + PH_HEAD(_floppy, raw_cmd->cmd[HEAD]);
2633*4882a593Smuzhiyun raw_cmd->cmd[GAP] = _floppy->gap;
2634*4882a593Smuzhiyun ssize = DIV_ROUND_UP(1 << raw_cmd->cmd[SIZECODE], 4);
2635*4882a593Smuzhiyun raw_cmd->cmd[SECT_PER_TRACK] = _floppy->sect << 2 >> raw_cmd->cmd[SIZECODE];
2636*4882a593Smuzhiyun raw_cmd->cmd[SECTOR] = ((fsector_t % _floppy->sect) << 2 >> raw_cmd->cmd[SIZECODE]) +
2637*4882a593Smuzhiyun FD_SECTBASE(_floppy);
2638*4882a593Smuzhiyun
2639*4882a593Smuzhiyun /* tracksize describes the size which can be filled up with sectors
2640*4882a593Smuzhiyun * of size ssize.
2641*4882a593Smuzhiyun */
2642*4882a593Smuzhiyun tracksize = _floppy->sect - _floppy->sect % ssize;
2643*4882a593Smuzhiyun if (tracksize < _floppy->sect) {
2644*4882a593Smuzhiyun raw_cmd->cmd[SECT_PER_TRACK]++;
2645*4882a593Smuzhiyun if (tracksize <= fsector_t % _floppy->sect)
2646*4882a593Smuzhiyun raw_cmd->cmd[SECTOR]--;
2647*4882a593Smuzhiyun
2648*4882a593Smuzhiyun /* if we are beyond tracksize, fill up using smaller sectors */
2649*4882a593Smuzhiyun while (tracksize <= fsector_t % _floppy->sect) {
2650*4882a593Smuzhiyun while (tracksize + ssize > _floppy->sect) {
2651*4882a593Smuzhiyun raw_cmd->cmd[SIZECODE]--;
2652*4882a593Smuzhiyun ssize >>= 1;
2653*4882a593Smuzhiyun }
2654*4882a593Smuzhiyun raw_cmd->cmd[SECTOR]++;
2655*4882a593Smuzhiyun raw_cmd->cmd[SECT_PER_TRACK]++;
2656*4882a593Smuzhiyun tracksize += ssize;
2657*4882a593Smuzhiyun }
2658*4882a593Smuzhiyun max_sector = raw_cmd->cmd[HEAD] * _floppy->sect + tracksize;
2659*4882a593Smuzhiyun } else if (!raw_cmd->cmd[TRACK] && !raw_cmd->cmd[HEAD] && !(_floppy->rate & FD_2M) && probing) {
2660*4882a593Smuzhiyun max_sector = _floppy->sect;
2661*4882a593Smuzhiyun } else if (!raw_cmd->cmd[HEAD] && CT(raw_cmd->cmd[COMMAND]) == FD_WRITE) {
2662*4882a593Smuzhiyun /* for virtual DMA bug workaround */
2663*4882a593Smuzhiyun max_sector = _floppy->sect;
2664*4882a593Smuzhiyun }
2665*4882a593Smuzhiyun
2666*4882a593Smuzhiyun in_sector_offset = (fsector_t % _floppy->sect) % ssize;
2667*4882a593Smuzhiyun aligned_sector_t = fsector_t - in_sector_offset;
2668*4882a593Smuzhiyun max_size = blk_rq_sectors(current_req);
2669*4882a593Smuzhiyun if ((raw_cmd->track == buffer_track) &&
2670*4882a593Smuzhiyun (current_drive == buffer_drive) &&
2671*4882a593Smuzhiyun (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
2672*4882a593Smuzhiyun /* data already in track buffer */
2673*4882a593Smuzhiyun if (CT(raw_cmd->cmd[COMMAND]) == FD_READ) {
2674*4882a593Smuzhiyun copy_buffer(1, max_sector, buffer_max);
2675*4882a593Smuzhiyun return 1;
2676*4882a593Smuzhiyun }
2677*4882a593Smuzhiyun } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
2678*4882a593Smuzhiyun if (CT(raw_cmd->cmd[COMMAND]) == FD_WRITE) {
2679*4882a593Smuzhiyun unsigned int sectors;
2680*4882a593Smuzhiyun
2681*4882a593Smuzhiyun sectors = fsector_t + blk_rq_sectors(current_req);
2682*4882a593Smuzhiyun if (sectors > ssize && sectors < ssize + ssize)
2683*4882a593Smuzhiyun max_size = ssize + ssize;
2684*4882a593Smuzhiyun else
2685*4882a593Smuzhiyun max_size = ssize;
2686*4882a593Smuzhiyun }
2687*4882a593Smuzhiyun raw_cmd->flags &= ~FD_RAW_WRITE;
2688*4882a593Smuzhiyun raw_cmd->flags |= FD_RAW_READ;
2689*4882a593Smuzhiyun raw_cmd->cmd[COMMAND] = FM_MODE(_floppy, FD_READ);
2690*4882a593Smuzhiyun } else if ((unsigned long)bio_data(current_req->bio) < MAX_DMA_ADDRESS) {
2691*4882a593Smuzhiyun unsigned long dma_limit;
2692*4882a593Smuzhiyun int direct, indirect;
2693*4882a593Smuzhiyun
2694*4882a593Smuzhiyun indirect =
2695*4882a593Smuzhiyun transfer_size(ssize, max_sector,
2696*4882a593Smuzhiyun max_buffer_sectors * 2) - fsector_t;
2697*4882a593Smuzhiyun
2698*4882a593Smuzhiyun /*
2699*4882a593Smuzhiyun * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide
2700*4882a593Smuzhiyun * on a 64 bit machine!
2701*4882a593Smuzhiyun */
2702*4882a593Smuzhiyun max_size = buffer_chain_size();
2703*4882a593Smuzhiyun dma_limit = (MAX_DMA_ADDRESS -
2704*4882a593Smuzhiyun ((unsigned long)bio_data(current_req->bio))) >> 9;
2705*4882a593Smuzhiyun if ((unsigned long)max_size > dma_limit)
2706*4882a593Smuzhiyun max_size = dma_limit;
2707*4882a593Smuzhiyun /* 64 kb boundaries */
2708*4882a593Smuzhiyun if (CROSS_64KB(bio_data(current_req->bio), max_size << 9))
2709*4882a593Smuzhiyun max_size = (K_64 -
2710*4882a593Smuzhiyun ((unsigned long)bio_data(current_req->bio)) %
2711*4882a593Smuzhiyun K_64) >> 9;
2712*4882a593Smuzhiyun direct = transfer_size(ssize, max_sector, max_size) - fsector_t;
2713*4882a593Smuzhiyun /*
2714*4882a593Smuzhiyun * We try to read tracks, but if we get too many errors, we
2715*4882a593Smuzhiyun * go back to reading just one sector at a time.
2716*4882a593Smuzhiyun *
2717*4882a593Smuzhiyun * This means we should be able to read a sector even if there
2718*4882a593Smuzhiyun * are other bad sectors on this track.
2719*4882a593Smuzhiyun */
2720*4882a593Smuzhiyun if (!direct ||
2721*4882a593Smuzhiyun (indirect * 2 > direct * 3 &&
2722*4882a593Smuzhiyun floppy_errors < drive_params[current_drive].max_errors.read_track &&
2723*4882a593Smuzhiyun ((!probing ||
2724*4882a593Smuzhiyun (drive_params[current_drive].read_track & (1 << drive_state[current_drive].probed_format)))))) {
2725*4882a593Smuzhiyun max_size = blk_rq_sectors(current_req);
2726*4882a593Smuzhiyun } else {
2727*4882a593Smuzhiyun raw_cmd->kernel_data = bio_data(current_req->bio);
2728*4882a593Smuzhiyun raw_cmd->length = current_count_sectors << 9;
2729*4882a593Smuzhiyun if (raw_cmd->length == 0) {
2730*4882a593Smuzhiyun DPRINT("%s: zero dma transfer attempted\n", __func__);
2731*4882a593Smuzhiyun DPRINT("indirect=%d direct=%d fsector_t=%d\n",
2732*4882a593Smuzhiyun indirect, direct, fsector_t);
2733*4882a593Smuzhiyun return 0;
2734*4882a593Smuzhiyun }
2735*4882a593Smuzhiyun virtualdmabug_workaround();
2736*4882a593Smuzhiyun return 2;
2737*4882a593Smuzhiyun }
2738*4882a593Smuzhiyun }
2739*4882a593Smuzhiyun
2740*4882a593Smuzhiyun if (CT(raw_cmd->cmd[COMMAND]) == FD_READ)
2741*4882a593Smuzhiyun max_size = max_sector; /* unbounded */
2742*4882a593Smuzhiyun
2743*4882a593Smuzhiyun /* claim buffer track if needed */
2744*4882a593Smuzhiyun if (buffer_track != raw_cmd->track || /* bad track */
2745*4882a593Smuzhiyun buffer_drive != current_drive || /* bad drive */
2746*4882a593Smuzhiyun fsector_t > buffer_max ||
2747*4882a593Smuzhiyun fsector_t < buffer_min ||
2748*4882a593Smuzhiyun ((CT(raw_cmd->cmd[COMMAND]) == FD_READ ||
2749*4882a593Smuzhiyun (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
2750*4882a593Smuzhiyun max_sector > 2 * max_buffer_sectors + buffer_min &&
2751*4882a593Smuzhiyun max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
2752*4882a593Smuzhiyun /* not enough space */
2753*4882a593Smuzhiyun buffer_track = -1;
2754*4882a593Smuzhiyun buffer_drive = current_drive;
2755*4882a593Smuzhiyun buffer_max = buffer_min = aligned_sector_t;
2756*4882a593Smuzhiyun }
2757*4882a593Smuzhiyun raw_cmd->kernel_data = floppy_track_buffer +
2758*4882a593Smuzhiyun ((aligned_sector_t - buffer_min) << 9);
2759*4882a593Smuzhiyun
2760*4882a593Smuzhiyun if (CT(raw_cmd->cmd[COMMAND]) == FD_WRITE) {
2761*4882a593Smuzhiyun /* copy write buffer to track buffer.
2762*4882a593Smuzhiyun * if we get here, we know that the write
2763*4882a593Smuzhiyun * is either aligned or the data already in the buffer
2764*4882a593Smuzhiyun * (buffer will be overwritten) */
2765*4882a593Smuzhiyun if (in_sector_offset && buffer_track == -1)
2766*4882a593Smuzhiyun DPRINT("internal error offset !=0 on write\n");
2767*4882a593Smuzhiyun buffer_track = raw_cmd->track;
2768*4882a593Smuzhiyun buffer_drive = current_drive;
2769*4882a593Smuzhiyun copy_buffer(ssize, max_sector,
2770*4882a593Smuzhiyun 2 * max_buffer_sectors + buffer_min);
2771*4882a593Smuzhiyun } else
2772*4882a593Smuzhiyun transfer_size(ssize, max_sector,
2773*4882a593Smuzhiyun 2 * max_buffer_sectors + buffer_min -
2774*4882a593Smuzhiyun aligned_sector_t);
2775*4882a593Smuzhiyun
2776*4882a593Smuzhiyun /* round up current_count_sectors to get dma xfer size */
2777*4882a593Smuzhiyun raw_cmd->length = in_sector_offset + current_count_sectors;
2778*4882a593Smuzhiyun raw_cmd->length = ((raw_cmd->length - 1) | (ssize - 1)) + 1;
2779*4882a593Smuzhiyun raw_cmd->length <<= 9;
2780*4882a593Smuzhiyun if ((raw_cmd->length < current_count_sectors << 9) ||
2781*4882a593Smuzhiyun (raw_cmd->kernel_data != bio_data(current_req->bio) &&
2782*4882a593Smuzhiyun CT(raw_cmd->cmd[COMMAND]) == FD_WRITE &&
2783*4882a593Smuzhiyun (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
2784*4882a593Smuzhiyun aligned_sector_t < buffer_min)) ||
2785*4882a593Smuzhiyun raw_cmd->length % (128 << raw_cmd->cmd[SIZECODE]) ||
2786*4882a593Smuzhiyun raw_cmd->length <= 0 || current_count_sectors <= 0) {
2787*4882a593Smuzhiyun DPRINT("fractionary current count b=%lx s=%lx\n",
2788*4882a593Smuzhiyun raw_cmd->length, current_count_sectors);
2789*4882a593Smuzhiyun if (raw_cmd->kernel_data != bio_data(current_req->bio))
2790*4882a593Smuzhiyun pr_info("addr=%d, length=%ld\n",
2791*4882a593Smuzhiyun (int)((raw_cmd->kernel_data -
2792*4882a593Smuzhiyun floppy_track_buffer) >> 9),
2793*4882a593Smuzhiyun current_count_sectors);
2794*4882a593Smuzhiyun pr_info("st=%d ast=%d mse=%d msi=%d\n",
2795*4882a593Smuzhiyun fsector_t, aligned_sector_t, max_sector, max_size);
2796*4882a593Smuzhiyun pr_info("ssize=%x SIZECODE=%d\n", ssize, raw_cmd->cmd[SIZECODE]);
2797*4882a593Smuzhiyun pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
2798*4882a593Smuzhiyun raw_cmd->cmd[COMMAND], raw_cmd->cmd[SECTOR],
2799*4882a593Smuzhiyun raw_cmd->cmd[HEAD], raw_cmd->cmd[TRACK]);
2800*4882a593Smuzhiyun pr_info("buffer drive=%d\n", buffer_drive);
2801*4882a593Smuzhiyun pr_info("buffer track=%d\n", buffer_track);
2802*4882a593Smuzhiyun pr_info("buffer_min=%d\n", buffer_min);
2803*4882a593Smuzhiyun pr_info("buffer_max=%d\n", buffer_max);
2804*4882a593Smuzhiyun return 0;
2805*4882a593Smuzhiyun }
2806*4882a593Smuzhiyun
2807*4882a593Smuzhiyun if (raw_cmd->kernel_data != bio_data(current_req->bio)) {
2808*4882a593Smuzhiyun if (raw_cmd->kernel_data < floppy_track_buffer ||
2809*4882a593Smuzhiyun current_count_sectors < 0 ||
2810*4882a593Smuzhiyun raw_cmd->length < 0 ||
2811*4882a593Smuzhiyun raw_cmd->kernel_data + raw_cmd->length >
2812*4882a593Smuzhiyun floppy_track_buffer + (max_buffer_sectors << 10)) {
2813*4882a593Smuzhiyun DPRINT("buffer overrun in schedule dma\n");
2814*4882a593Smuzhiyun pr_info("fsector_t=%d buffer_min=%d current_count=%ld\n",
2815*4882a593Smuzhiyun fsector_t, buffer_min, raw_cmd->length >> 9);
2816*4882a593Smuzhiyun pr_info("current_count_sectors=%ld\n",
2817*4882a593Smuzhiyun current_count_sectors);
2818*4882a593Smuzhiyun if (CT(raw_cmd->cmd[COMMAND]) == FD_READ)
2819*4882a593Smuzhiyun pr_info("read\n");
2820*4882a593Smuzhiyun if (CT(raw_cmd->cmd[COMMAND]) == FD_WRITE)
2821*4882a593Smuzhiyun pr_info("write\n");
2822*4882a593Smuzhiyun return 0;
2823*4882a593Smuzhiyun }
2824*4882a593Smuzhiyun } else if (raw_cmd->length > blk_rq_bytes(current_req) ||
2825*4882a593Smuzhiyun current_count_sectors > blk_rq_sectors(current_req)) {
2826*4882a593Smuzhiyun DPRINT("buffer overrun in direct transfer\n");
2827*4882a593Smuzhiyun return 0;
2828*4882a593Smuzhiyun } else if (raw_cmd->length < current_count_sectors << 9) {
2829*4882a593Smuzhiyun DPRINT("more sectors than bytes\n");
2830*4882a593Smuzhiyun pr_info("bytes=%ld\n", raw_cmd->length >> 9);
2831*4882a593Smuzhiyun pr_info("sectors=%ld\n", current_count_sectors);
2832*4882a593Smuzhiyun }
2833*4882a593Smuzhiyun if (raw_cmd->length == 0) {
2834*4882a593Smuzhiyun DPRINT("zero dma transfer attempted from make_raw_request\n");
2835*4882a593Smuzhiyun return 0;
2836*4882a593Smuzhiyun }
2837*4882a593Smuzhiyun
2838*4882a593Smuzhiyun virtualdmabug_workaround();
2839*4882a593Smuzhiyun return 2;
2840*4882a593Smuzhiyun }
2841*4882a593Smuzhiyun
set_next_request(void)2842*4882a593Smuzhiyun static int set_next_request(void)
2843*4882a593Smuzhiyun {
2844*4882a593Smuzhiyun current_req = list_first_entry_or_null(&floppy_reqs, struct request,
2845*4882a593Smuzhiyun queuelist);
2846*4882a593Smuzhiyun if (current_req) {
2847*4882a593Smuzhiyun floppy_errors = 0;
2848*4882a593Smuzhiyun list_del_init(¤t_req->queuelist);
2849*4882a593Smuzhiyun return 1;
2850*4882a593Smuzhiyun }
2851*4882a593Smuzhiyun return 0;
2852*4882a593Smuzhiyun }
2853*4882a593Smuzhiyun
2854*4882a593Smuzhiyun /* Starts or continues processing request. Will automatically unlock the
2855*4882a593Smuzhiyun * driver at end of request.
2856*4882a593Smuzhiyun */
redo_fd_request(void)2857*4882a593Smuzhiyun static void redo_fd_request(void)
2858*4882a593Smuzhiyun {
2859*4882a593Smuzhiyun int drive;
2860*4882a593Smuzhiyun int tmp;
2861*4882a593Smuzhiyun
2862*4882a593Smuzhiyun lastredo = jiffies;
2863*4882a593Smuzhiyun if (current_drive < N_DRIVE)
2864*4882a593Smuzhiyun floppy_off(current_drive);
2865*4882a593Smuzhiyun
2866*4882a593Smuzhiyun do_request:
2867*4882a593Smuzhiyun if (!current_req) {
2868*4882a593Smuzhiyun int pending;
2869*4882a593Smuzhiyun
2870*4882a593Smuzhiyun spin_lock_irq(&floppy_lock);
2871*4882a593Smuzhiyun pending = set_next_request();
2872*4882a593Smuzhiyun spin_unlock_irq(&floppy_lock);
2873*4882a593Smuzhiyun if (!pending) {
2874*4882a593Smuzhiyun do_floppy = NULL;
2875*4882a593Smuzhiyun unlock_fdc();
2876*4882a593Smuzhiyun return;
2877*4882a593Smuzhiyun }
2878*4882a593Smuzhiyun }
2879*4882a593Smuzhiyun drive = (long)current_req->rq_disk->private_data;
2880*4882a593Smuzhiyun set_fdc(drive);
2881*4882a593Smuzhiyun reschedule_timeout(current_drive, "redo fd request");
2882*4882a593Smuzhiyun
2883*4882a593Smuzhiyun set_floppy(drive);
2884*4882a593Smuzhiyun raw_cmd = &default_raw_cmd;
2885*4882a593Smuzhiyun raw_cmd->flags = 0;
2886*4882a593Smuzhiyun if (start_motor(redo_fd_request))
2887*4882a593Smuzhiyun return;
2888*4882a593Smuzhiyun
2889*4882a593Smuzhiyun disk_change(current_drive);
2890*4882a593Smuzhiyun if (test_bit(current_drive, &fake_change) ||
2891*4882a593Smuzhiyun test_bit(FD_DISK_CHANGED_BIT, &drive_state[current_drive].flags)) {
2892*4882a593Smuzhiyun DPRINT("disk absent or changed during operation\n");
2893*4882a593Smuzhiyun request_done(0);
2894*4882a593Smuzhiyun goto do_request;
2895*4882a593Smuzhiyun }
2896*4882a593Smuzhiyun if (!_floppy) { /* Autodetection */
2897*4882a593Smuzhiyun if (!probing) {
2898*4882a593Smuzhiyun drive_state[current_drive].probed_format = 0;
2899*4882a593Smuzhiyun if (next_valid_format(current_drive)) {
2900*4882a593Smuzhiyun DPRINT("no autodetectable formats\n");
2901*4882a593Smuzhiyun _floppy = NULL;
2902*4882a593Smuzhiyun request_done(0);
2903*4882a593Smuzhiyun goto do_request;
2904*4882a593Smuzhiyun }
2905*4882a593Smuzhiyun }
2906*4882a593Smuzhiyun probing = 1;
2907*4882a593Smuzhiyun _floppy = floppy_type + drive_params[current_drive].autodetect[drive_state[current_drive].probed_format];
2908*4882a593Smuzhiyun } else
2909*4882a593Smuzhiyun probing = 0;
2910*4882a593Smuzhiyun tmp = make_raw_rw_request();
2911*4882a593Smuzhiyun if (tmp < 2) {
2912*4882a593Smuzhiyun request_done(tmp);
2913*4882a593Smuzhiyun goto do_request;
2914*4882a593Smuzhiyun }
2915*4882a593Smuzhiyun
2916*4882a593Smuzhiyun if (test_bit(FD_NEED_TWADDLE_BIT, &drive_state[current_drive].flags))
2917*4882a593Smuzhiyun twaddle(current_fdc, current_drive);
2918*4882a593Smuzhiyun schedule_bh(floppy_start);
2919*4882a593Smuzhiyun debugt(__func__, "queue fd request");
2920*4882a593Smuzhiyun return;
2921*4882a593Smuzhiyun }
2922*4882a593Smuzhiyun
2923*4882a593Smuzhiyun static const struct cont_t rw_cont = {
2924*4882a593Smuzhiyun .interrupt = rw_interrupt,
2925*4882a593Smuzhiyun .redo = redo_fd_request,
2926*4882a593Smuzhiyun .error = bad_flp_intr,
2927*4882a593Smuzhiyun .done = request_done
2928*4882a593Smuzhiyun };
2929*4882a593Smuzhiyun
2930*4882a593Smuzhiyun /* schedule the request and automatically unlock the driver on completion */
process_fd_request(void)2931*4882a593Smuzhiyun static void process_fd_request(void)
2932*4882a593Smuzhiyun {
2933*4882a593Smuzhiyun cont = &rw_cont;
2934*4882a593Smuzhiyun schedule_bh(redo_fd_request);
2935*4882a593Smuzhiyun }
2936*4882a593Smuzhiyun
floppy_queue_rq(struct blk_mq_hw_ctx * hctx,const struct blk_mq_queue_data * bd)2937*4882a593Smuzhiyun static blk_status_t floppy_queue_rq(struct blk_mq_hw_ctx *hctx,
2938*4882a593Smuzhiyun const struct blk_mq_queue_data *bd)
2939*4882a593Smuzhiyun {
2940*4882a593Smuzhiyun blk_mq_start_request(bd->rq);
2941*4882a593Smuzhiyun
2942*4882a593Smuzhiyun if (WARN(max_buffer_sectors == 0,
2943*4882a593Smuzhiyun "VFS: %s called on non-open device\n", __func__))
2944*4882a593Smuzhiyun return BLK_STS_IOERR;
2945*4882a593Smuzhiyun
2946*4882a593Smuzhiyun if (WARN(atomic_read(&usage_count) == 0,
2947*4882a593Smuzhiyun "warning: usage count=0, current_req=%p sect=%ld flags=%llx\n",
2948*4882a593Smuzhiyun current_req, (long)blk_rq_pos(current_req),
2949*4882a593Smuzhiyun (unsigned long long) current_req->cmd_flags))
2950*4882a593Smuzhiyun return BLK_STS_IOERR;
2951*4882a593Smuzhiyun
2952*4882a593Smuzhiyun if (test_and_set_bit(0, &fdc_busy)) {
2953*4882a593Smuzhiyun /* fdc busy, this new request will be treated when the
2954*4882a593Smuzhiyun current one is done */
2955*4882a593Smuzhiyun is_alive(__func__, "old request running");
2956*4882a593Smuzhiyun return BLK_STS_RESOURCE;
2957*4882a593Smuzhiyun }
2958*4882a593Smuzhiyun
2959*4882a593Smuzhiyun spin_lock_irq(&floppy_lock);
2960*4882a593Smuzhiyun list_add_tail(&bd->rq->queuelist, &floppy_reqs);
2961*4882a593Smuzhiyun spin_unlock_irq(&floppy_lock);
2962*4882a593Smuzhiyun
2963*4882a593Smuzhiyun command_status = FD_COMMAND_NONE;
2964*4882a593Smuzhiyun __reschedule_timeout(MAXTIMEOUT, "fd_request");
2965*4882a593Smuzhiyun set_fdc(0);
2966*4882a593Smuzhiyun process_fd_request();
2967*4882a593Smuzhiyun is_alive(__func__, "");
2968*4882a593Smuzhiyun return BLK_STS_OK;
2969*4882a593Smuzhiyun }
2970*4882a593Smuzhiyun
2971*4882a593Smuzhiyun static const struct cont_t poll_cont = {
2972*4882a593Smuzhiyun .interrupt = success_and_wakeup,
2973*4882a593Smuzhiyun .redo = floppy_ready,
2974*4882a593Smuzhiyun .error = generic_failure,
2975*4882a593Smuzhiyun .done = generic_done
2976*4882a593Smuzhiyun };
2977*4882a593Smuzhiyun
poll_drive(bool interruptible,int flag)2978*4882a593Smuzhiyun static int poll_drive(bool interruptible, int flag)
2979*4882a593Smuzhiyun {
2980*4882a593Smuzhiyun /* no auto-sense, just clear dcl */
2981*4882a593Smuzhiyun raw_cmd = &default_raw_cmd;
2982*4882a593Smuzhiyun raw_cmd->flags = flag;
2983*4882a593Smuzhiyun raw_cmd->track = 0;
2984*4882a593Smuzhiyun raw_cmd->cmd_count = 0;
2985*4882a593Smuzhiyun cont = &poll_cont;
2986*4882a593Smuzhiyun debug_dcl(drive_params[current_drive].flags,
2987*4882a593Smuzhiyun "setting NEWCHANGE in poll_drive\n");
2988*4882a593Smuzhiyun set_bit(FD_DISK_NEWCHANGE_BIT, &drive_state[current_drive].flags);
2989*4882a593Smuzhiyun
2990*4882a593Smuzhiyun return wait_til_done(floppy_ready, interruptible);
2991*4882a593Smuzhiyun }
2992*4882a593Smuzhiyun
2993*4882a593Smuzhiyun /*
2994*4882a593Smuzhiyun * User triggered reset
2995*4882a593Smuzhiyun * ====================
2996*4882a593Smuzhiyun */
2997*4882a593Smuzhiyun
reset_intr(void)2998*4882a593Smuzhiyun static void reset_intr(void)
2999*4882a593Smuzhiyun {
3000*4882a593Smuzhiyun pr_info("weird, reset interrupt called\n");
3001*4882a593Smuzhiyun }
3002*4882a593Smuzhiyun
3003*4882a593Smuzhiyun static const struct cont_t reset_cont = {
3004*4882a593Smuzhiyun .interrupt = reset_intr,
3005*4882a593Smuzhiyun .redo = success_and_wakeup,
3006*4882a593Smuzhiyun .error = generic_failure,
3007*4882a593Smuzhiyun .done = generic_done
3008*4882a593Smuzhiyun };
3009*4882a593Smuzhiyun
3010*4882a593Smuzhiyun /*
3011*4882a593Smuzhiyun * Resets the FDC connected to drive <drive>.
3012*4882a593Smuzhiyun * Both current_drive and current_fdc are changed to match the new drive.
3013*4882a593Smuzhiyun */
user_reset_fdc(int drive,int arg,bool interruptible)3014*4882a593Smuzhiyun static int user_reset_fdc(int drive, int arg, bool interruptible)
3015*4882a593Smuzhiyun {
3016*4882a593Smuzhiyun int ret;
3017*4882a593Smuzhiyun
3018*4882a593Smuzhiyun if (lock_fdc(drive))
3019*4882a593Smuzhiyun return -EINTR;
3020*4882a593Smuzhiyun
3021*4882a593Smuzhiyun if (arg == FD_RESET_ALWAYS)
3022*4882a593Smuzhiyun fdc_state[current_fdc].reset = 1;
3023*4882a593Smuzhiyun if (fdc_state[current_fdc].reset) {
3024*4882a593Smuzhiyun /* note: reset_fdc will take care of unlocking the driver
3025*4882a593Smuzhiyun * on completion.
3026*4882a593Smuzhiyun */
3027*4882a593Smuzhiyun cont = &reset_cont;
3028*4882a593Smuzhiyun ret = wait_til_done(reset_fdc, interruptible);
3029*4882a593Smuzhiyun if (ret == -EINTR)
3030*4882a593Smuzhiyun return -EINTR;
3031*4882a593Smuzhiyun }
3032*4882a593Smuzhiyun process_fd_request();
3033*4882a593Smuzhiyun return 0;
3034*4882a593Smuzhiyun }
3035*4882a593Smuzhiyun
3036*4882a593Smuzhiyun /*
3037*4882a593Smuzhiyun * Misc Ioctl's and support
3038*4882a593Smuzhiyun * ========================
3039*4882a593Smuzhiyun */
fd_copyout(void __user * param,const void * address,unsigned long size)3040*4882a593Smuzhiyun static inline int fd_copyout(void __user *param, const void *address,
3041*4882a593Smuzhiyun unsigned long size)
3042*4882a593Smuzhiyun {
3043*4882a593Smuzhiyun return copy_to_user(param, address, size) ? -EFAULT : 0;
3044*4882a593Smuzhiyun }
3045*4882a593Smuzhiyun
fd_copyin(void __user * param,void * address,unsigned long size)3046*4882a593Smuzhiyun static inline int fd_copyin(void __user *param, void *address,
3047*4882a593Smuzhiyun unsigned long size)
3048*4882a593Smuzhiyun {
3049*4882a593Smuzhiyun return copy_from_user(address, param, size) ? -EFAULT : 0;
3050*4882a593Smuzhiyun }
3051*4882a593Smuzhiyun
drive_name(int type,int drive)3052*4882a593Smuzhiyun static const char *drive_name(int type, int drive)
3053*4882a593Smuzhiyun {
3054*4882a593Smuzhiyun struct floppy_struct *floppy;
3055*4882a593Smuzhiyun
3056*4882a593Smuzhiyun if (type)
3057*4882a593Smuzhiyun floppy = floppy_type + type;
3058*4882a593Smuzhiyun else {
3059*4882a593Smuzhiyun if (drive_params[drive].native_format)
3060*4882a593Smuzhiyun floppy = floppy_type + drive_params[drive].native_format;
3061*4882a593Smuzhiyun else
3062*4882a593Smuzhiyun return "(null)";
3063*4882a593Smuzhiyun }
3064*4882a593Smuzhiyun if (floppy->name)
3065*4882a593Smuzhiyun return floppy->name;
3066*4882a593Smuzhiyun else
3067*4882a593Smuzhiyun return "(null)";
3068*4882a593Smuzhiyun }
3069*4882a593Smuzhiyun
3070*4882a593Smuzhiyun #ifdef CONFIG_BLK_DEV_FD_RAWCMD
3071*4882a593Smuzhiyun
3072*4882a593Smuzhiyun /* raw commands */
raw_cmd_done(int flag)3073*4882a593Smuzhiyun static void raw_cmd_done(int flag)
3074*4882a593Smuzhiyun {
3075*4882a593Smuzhiyun int i;
3076*4882a593Smuzhiyun
3077*4882a593Smuzhiyun if (!flag) {
3078*4882a593Smuzhiyun raw_cmd->flags |= FD_RAW_FAILURE;
3079*4882a593Smuzhiyun raw_cmd->flags |= FD_RAW_HARDFAILURE;
3080*4882a593Smuzhiyun } else {
3081*4882a593Smuzhiyun raw_cmd->reply_count = inr;
3082*4882a593Smuzhiyun if (raw_cmd->reply_count > FD_RAW_REPLY_SIZE)
3083*4882a593Smuzhiyun raw_cmd->reply_count = 0;
3084*4882a593Smuzhiyun for (i = 0; i < raw_cmd->reply_count; i++)
3085*4882a593Smuzhiyun raw_cmd->reply[i] = reply_buffer[i];
3086*4882a593Smuzhiyun
3087*4882a593Smuzhiyun if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3088*4882a593Smuzhiyun unsigned long flags;
3089*4882a593Smuzhiyun flags = claim_dma_lock();
3090*4882a593Smuzhiyun raw_cmd->length = fd_get_dma_residue();
3091*4882a593Smuzhiyun release_dma_lock(flags);
3092*4882a593Smuzhiyun }
3093*4882a593Smuzhiyun
3094*4882a593Smuzhiyun if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) &&
3095*4882a593Smuzhiyun (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0)))
3096*4882a593Smuzhiyun raw_cmd->flags |= FD_RAW_FAILURE;
3097*4882a593Smuzhiyun
3098*4882a593Smuzhiyun if (disk_change(current_drive))
3099*4882a593Smuzhiyun raw_cmd->flags |= FD_RAW_DISK_CHANGE;
3100*4882a593Smuzhiyun else
3101*4882a593Smuzhiyun raw_cmd->flags &= ~FD_RAW_DISK_CHANGE;
3102*4882a593Smuzhiyun if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER)
3103*4882a593Smuzhiyun motor_off_callback(&motor_off_timer[current_drive]);
3104*4882a593Smuzhiyun
3105*4882a593Smuzhiyun if (raw_cmd->next &&
3106*4882a593Smuzhiyun (!(raw_cmd->flags & FD_RAW_FAILURE) ||
3107*4882a593Smuzhiyun !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) &&
3108*4882a593Smuzhiyun ((raw_cmd->flags & FD_RAW_FAILURE) ||
3109*4882a593Smuzhiyun !(raw_cmd->flags & FD_RAW_STOP_IF_SUCCESS))) {
3110*4882a593Smuzhiyun raw_cmd = raw_cmd->next;
3111*4882a593Smuzhiyun return;
3112*4882a593Smuzhiyun }
3113*4882a593Smuzhiyun }
3114*4882a593Smuzhiyun generic_done(flag);
3115*4882a593Smuzhiyun }
3116*4882a593Smuzhiyun
3117*4882a593Smuzhiyun static const struct cont_t raw_cmd_cont = {
3118*4882a593Smuzhiyun .interrupt = success_and_wakeup,
3119*4882a593Smuzhiyun .redo = floppy_start,
3120*4882a593Smuzhiyun .error = generic_failure,
3121*4882a593Smuzhiyun .done = raw_cmd_done
3122*4882a593Smuzhiyun };
3123*4882a593Smuzhiyun
raw_cmd_copyout(int cmd,void __user * param,struct floppy_raw_cmd * ptr)3124*4882a593Smuzhiyun static int raw_cmd_copyout(int cmd, void __user *param,
3125*4882a593Smuzhiyun struct floppy_raw_cmd *ptr)
3126*4882a593Smuzhiyun {
3127*4882a593Smuzhiyun int ret;
3128*4882a593Smuzhiyun
3129*4882a593Smuzhiyun while (ptr) {
3130*4882a593Smuzhiyun struct floppy_raw_cmd cmd = *ptr;
3131*4882a593Smuzhiyun cmd.next = NULL;
3132*4882a593Smuzhiyun cmd.kernel_data = NULL;
3133*4882a593Smuzhiyun ret = copy_to_user(param, &cmd, sizeof(cmd));
3134*4882a593Smuzhiyun if (ret)
3135*4882a593Smuzhiyun return -EFAULT;
3136*4882a593Smuzhiyun param += sizeof(struct floppy_raw_cmd);
3137*4882a593Smuzhiyun if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length) {
3138*4882a593Smuzhiyun if (ptr->length >= 0 &&
3139*4882a593Smuzhiyun ptr->length <= ptr->buffer_length) {
3140*4882a593Smuzhiyun long length = ptr->buffer_length - ptr->length;
3141*4882a593Smuzhiyun ret = fd_copyout(ptr->data, ptr->kernel_data,
3142*4882a593Smuzhiyun length);
3143*4882a593Smuzhiyun if (ret)
3144*4882a593Smuzhiyun return ret;
3145*4882a593Smuzhiyun }
3146*4882a593Smuzhiyun }
3147*4882a593Smuzhiyun ptr = ptr->next;
3148*4882a593Smuzhiyun }
3149*4882a593Smuzhiyun
3150*4882a593Smuzhiyun return 0;
3151*4882a593Smuzhiyun }
3152*4882a593Smuzhiyun
raw_cmd_free(struct floppy_raw_cmd ** ptr)3153*4882a593Smuzhiyun static void raw_cmd_free(struct floppy_raw_cmd **ptr)
3154*4882a593Smuzhiyun {
3155*4882a593Smuzhiyun struct floppy_raw_cmd *next;
3156*4882a593Smuzhiyun struct floppy_raw_cmd *this;
3157*4882a593Smuzhiyun
3158*4882a593Smuzhiyun this = *ptr;
3159*4882a593Smuzhiyun *ptr = NULL;
3160*4882a593Smuzhiyun while (this) {
3161*4882a593Smuzhiyun if (this->buffer_length) {
3162*4882a593Smuzhiyun fd_dma_mem_free((unsigned long)this->kernel_data,
3163*4882a593Smuzhiyun this->buffer_length);
3164*4882a593Smuzhiyun this->buffer_length = 0;
3165*4882a593Smuzhiyun }
3166*4882a593Smuzhiyun next = this->next;
3167*4882a593Smuzhiyun kfree(this);
3168*4882a593Smuzhiyun this = next;
3169*4882a593Smuzhiyun }
3170*4882a593Smuzhiyun }
3171*4882a593Smuzhiyun
3172*4882a593Smuzhiyun #define MAX_LEN (1UL << MAX_ORDER << PAGE_SHIFT)
3173*4882a593Smuzhiyun
raw_cmd_copyin(int cmd,void __user * param,struct floppy_raw_cmd ** rcmd)3174*4882a593Smuzhiyun static int raw_cmd_copyin(int cmd, void __user *param,
3175*4882a593Smuzhiyun struct floppy_raw_cmd **rcmd)
3176*4882a593Smuzhiyun {
3177*4882a593Smuzhiyun struct floppy_raw_cmd *ptr;
3178*4882a593Smuzhiyun int ret;
3179*4882a593Smuzhiyun int i;
3180*4882a593Smuzhiyun
3181*4882a593Smuzhiyun *rcmd = NULL;
3182*4882a593Smuzhiyun
3183*4882a593Smuzhiyun loop:
3184*4882a593Smuzhiyun ptr = kmalloc(sizeof(struct floppy_raw_cmd), GFP_KERNEL);
3185*4882a593Smuzhiyun if (!ptr)
3186*4882a593Smuzhiyun return -ENOMEM;
3187*4882a593Smuzhiyun *rcmd = ptr;
3188*4882a593Smuzhiyun ret = copy_from_user(ptr, param, sizeof(*ptr));
3189*4882a593Smuzhiyun ptr->next = NULL;
3190*4882a593Smuzhiyun ptr->buffer_length = 0;
3191*4882a593Smuzhiyun ptr->kernel_data = NULL;
3192*4882a593Smuzhiyun if (ret)
3193*4882a593Smuzhiyun return -EFAULT;
3194*4882a593Smuzhiyun param += sizeof(struct floppy_raw_cmd);
3195*4882a593Smuzhiyun if (ptr->cmd_count > FD_RAW_CMD_FULLSIZE)
3196*4882a593Smuzhiyun return -EINVAL;
3197*4882a593Smuzhiyun
3198*4882a593Smuzhiyun for (i = 0; i < FD_RAW_REPLY_SIZE; i++)
3199*4882a593Smuzhiyun ptr->reply[i] = 0;
3200*4882a593Smuzhiyun ptr->resultcode = 0;
3201*4882a593Smuzhiyun
3202*4882a593Smuzhiyun if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) {
3203*4882a593Smuzhiyun if (ptr->length <= 0 || ptr->length >= MAX_LEN)
3204*4882a593Smuzhiyun return -EINVAL;
3205*4882a593Smuzhiyun ptr->kernel_data = (char *)fd_dma_mem_alloc(ptr->length);
3206*4882a593Smuzhiyun fallback_on_nodma_alloc(&ptr->kernel_data, ptr->length);
3207*4882a593Smuzhiyun if (!ptr->kernel_data)
3208*4882a593Smuzhiyun return -ENOMEM;
3209*4882a593Smuzhiyun ptr->buffer_length = ptr->length;
3210*4882a593Smuzhiyun }
3211*4882a593Smuzhiyun if (ptr->flags & FD_RAW_WRITE) {
3212*4882a593Smuzhiyun ret = fd_copyin(ptr->data, ptr->kernel_data, ptr->length);
3213*4882a593Smuzhiyun if (ret)
3214*4882a593Smuzhiyun return ret;
3215*4882a593Smuzhiyun }
3216*4882a593Smuzhiyun
3217*4882a593Smuzhiyun if (ptr->flags & FD_RAW_MORE) {
3218*4882a593Smuzhiyun rcmd = &(ptr->next);
3219*4882a593Smuzhiyun ptr->rate &= 0x43;
3220*4882a593Smuzhiyun goto loop;
3221*4882a593Smuzhiyun }
3222*4882a593Smuzhiyun
3223*4882a593Smuzhiyun return 0;
3224*4882a593Smuzhiyun }
3225*4882a593Smuzhiyun
raw_cmd_ioctl(int cmd,void __user * param)3226*4882a593Smuzhiyun static int raw_cmd_ioctl(int cmd, void __user *param)
3227*4882a593Smuzhiyun {
3228*4882a593Smuzhiyun struct floppy_raw_cmd *my_raw_cmd;
3229*4882a593Smuzhiyun int drive;
3230*4882a593Smuzhiyun int ret2;
3231*4882a593Smuzhiyun int ret;
3232*4882a593Smuzhiyun
3233*4882a593Smuzhiyun if (fdc_state[current_fdc].rawcmd <= 1)
3234*4882a593Smuzhiyun fdc_state[current_fdc].rawcmd = 1;
3235*4882a593Smuzhiyun for (drive = 0; drive < N_DRIVE; drive++) {
3236*4882a593Smuzhiyun if (FDC(drive) != current_fdc)
3237*4882a593Smuzhiyun continue;
3238*4882a593Smuzhiyun if (drive == current_drive) {
3239*4882a593Smuzhiyun if (drive_state[drive].fd_ref > 1) {
3240*4882a593Smuzhiyun fdc_state[current_fdc].rawcmd = 2;
3241*4882a593Smuzhiyun break;
3242*4882a593Smuzhiyun }
3243*4882a593Smuzhiyun } else if (drive_state[drive].fd_ref) {
3244*4882a593Smuzhiyun fdc_state[current_fdc].rawcmd = 2;
3245*4882a593Smuzhiyun break;
3246*4882a593Smuzhiyun }
3247*4882a593Smuzhiyun }
3248*4882a593Smuzhiyun
3249*4882a593Smuzhiyun if (fdc_state[current_fdc].reset)
3250*4882a593Smuzhiyun return -EIO;
3251*4882a593Smuzhiyun
3252*4882a593Smuzhiyun ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
3253*4882a593Smuzhiyun if (ret) {
3254*4882a593Smuzhiyun raw_cmd_free(&my_raw_cmd);
3255*4882a593Smuzhiyun return ret;
3256*4882a593Smuzhiyun }
3257*4882a593Smuzhiyun
3258*4882a593Smuzhiyun raw_cmd = my_raw_cmd;
3259*4882a593Smuzhiyun cont = &raw_cmd_cont;
3260*4882a593Smuzhiyun ret = wait_til_done(floppy_start, true);
3261*4882a593Smuzhiyun debug_dcl(drive_params[current_drive].flags,
3262*4882a593Smuzhiyun "calling disk change from raw_cmd ioctl\n");
3263*4882a593Smuzhiyun
3264*4882a593Smuzhiyun if (ret != -EINTR && fdc_state[current_fdc].reset)
3265*4882a593Smuzhiyun ret = -EIO;
3266*4882a593Smuzhiyun
3267*4882a593Smuzhiyun drive_state[current_drive].track = NO_TRACK;
3268*4882a593Smuzhiyun
3269*4882a593Smuzhiyun ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
3270*4882a593Smuzhiyun if (!ret)
3271*4882a593Smuzhiyun ret = ret2;
3272*4882a593Smuzhiyun raw_cmd_free(&my_raw_cmd);
3273*4882a593Smuzhiyun return ret;
3274*4882a593Smuzhiyun }
3275*4882a593Smuzhiyun
floppy_raw_cmd_ioctl(int type,int drive,int cmd,void __user * param)3276*4882a593Smuzhiyun static int floppy_raw_cmd_ioctl(int type, int drive, int cmd,
3277*4882a593Smuzhiyun void __user *param)
3278*4882a593Smuzhiyun {
3279*4882a593Smuzhiyun int ret;
3280*4882a593Smuzhiyun
3281*4882a593Smuzhiyun pr_warn_once("Note: FDRAWCMD is deprecated and will be removed from the kernel in the near future.\n");
3282*4882a593Smuzhiyun
3283*4882a593Smuzhiyun if (type)
3284*4882a593Smuzhiyun return -EINVAL;
3285*4882a593Smuzhiyun if (lock_fdc(drive))
3286*4882a593Smuzhiyun return -EINTR;
3287*4882a593Smuzhiyun set_floppy(drive);
3288*4882a593Smuzhiyun ret = raw_cmd_ioctl(cmd, param);
3289*4882a593Smuzhiyun if (ret == -EINTR)
3290*4882a593Smuzhiyun return -EINTR;
3291*4882a593Smuzhiyun process_fd_request();
3292*4882a593Smuzhiyun return ret;
3293*4882a593Smuzhiyun }
3294*4882a593Smuzhiyun
3295*4882a593Smuzhiyun #else /* CONFIG_BLK_DEV_FD_RAWCMD */
3296*4882a593Smuzhiyun
floppy_raw_cmd_ioctl(int type,int drive,int cmd,void __user * param)3297*4882a593Smuzhiyun static int floppy_raw_cmd_ioctl(int type, int drive, int cmd,
3298*4882a593Smuzhiyun void __user *param)
3299*4882a593Smuzhiyun {
3300*4882a593Smuzhiyun return -EOPNOTSUPP;
3301*4882a593Smuzhiyun }
3302*4882a593Smuzhiyun
3303*4882a593Smuzhiyun #endif
3304*4882a593Smuzhiyun
invalidate_drive(struct block_device * bdev)3305*4882a593Smuzhiyun static int invalidate_drive(struct block_device *bdev)
3306*4882a593Smuzhiyun {
3307*4882a593Smuzhiyun /* invalidate the buffer track to force a reread */
3308*4882a593Smuzhiyun set_bit((long)bdev->bd_disk->private_data, &fake_change);
3309*4882a593Smuzhiyun process_fd_request();
3310*4882a593Smuzhiyun if (bdev_check_media_change(bdev))
3311*4882a593Smuzhiyun floppy_revalidate(bdev->bd_disk);
3312*4882a593Smuzhiyun return 0;
3313*4882a593Smuzhiyun }
3314*4882a593Smuzhiyun
set_geometry(unsigned int cmd,struct floppy_struct * g,int drive,int type,struct block_device * bdev)3315*4882a593Smuzhiyun static int set_geometry(unsigned int cmd, struct floppy_struct *g,
3316*4882a593Smuzhiyun int drive, int type, struct block_device *bdev)
3317*4882a593Smuzhiyun {
3318*4882a593Smuzhiyun int cnt;
3319*4882a593Smuzhiyun
3320*4882a593Smuzhiyun /* sanity checking for parameters. */
3321*4882a593Smuzhiyun if ((int)g->sect <= 0 ||
3322*4882a593Smuzhiyun (int)g->head <= 0 ||
3323*4882a593Smuzhiyun /* check for overflow in max_sector */
3324*4882a593Smuzhiyun (int)(g->sect * g->head) <= 0 ||
3325*4882a593Smuzhiyun /* check for zero in raw_cmd->cmd[F_SECT_PER_TRACK] */
3326*4882a593Smuzhiyun (unsigned char)((g->sect << 2) >> FD_SIZECODE(g)) == 0 ||
3327*4882a593Smuzhiyun g->track <= 0 || g->track > drive_params[drive].tracks >> STRETCH(g) ||
3328*4882a593Smuzhiyun /* check if reserved bits are set */
3329*4882a593Smuzhiyun (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
3330*4882a593Smuzhiyun return -EINVAL;
3331*4882a593Smuzhiyun if (type) {
3332*4882a593Smuzhiyun if (!capable(CAP_SYS_ADMIN))
3333*4882a593Smuzhiyun return -EPERM;
3334*4882a593Smuzhiyun mutex_lock(&open_lock);
3335*4882a593Smuzhiyun if (lock_fdc(drive)) {
3336*4882a593Smuzhiyun mutex_unlock(&open_lock);
3337*4882a593Smuzhiyun return -EINTR;
3338*4882a593Smuzhiyun }
3339*4882a593Smuzhiyun floppy_type[type] = *g;
3340*4882a593Smuzhiyun floppy_type[type].name = "user format";
3341*4882a593Smuzhiyun for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
3342*4882a593Smuzhiyun floppy_sizes[cnt] = floppy_sizes[cnt + 0x80] =
3343*4882a593Smuzhiyun floppy_type[type].size + 1;
3344*4882a593Smuzhiyun process_fd_request();
3345*4882a593Smuzhiyun for (cnt = 0; cnt < N_DRIVE; cnt++) {
3346*4882a593Smuzhiyun struct block_device *bdev = opened_bdev[cnt];
3347*4882a593Smuzhiyun if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
3348*4882a593Smuzhiyun continue;
3349*4882a593Smuzhiyun __invalidate_device(bdev, true);
3350*4882a593Smuzhiyun }
3351*4882a593Smuzhiyun mutex_unlock(&open_lock);
3352*4882a593Smuzhiyun } else {
3353*4882a593Smuzhiyun int oldStretch;
3354*4882a593Smuzhiyun
3355*4882a593Smuzhiyun if (lock_fdc(drive))
3356*4882a593Smuzhiyun return -EINTR;
3357*4882a593Smuzhiyun if (cmd != FDDEFPRM) {
3358*4882a593Smuzhiyun /* notice a disk change immediately, else
3359*4882a593Smuzhiyun * we lose our settings immediately*/
3360*4882a593Smuzhiyun if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
3361*4882a593Smuzhiyun return -EINTR;
3362*4882a593Smuzhiyun }
3363*4882a593Smuzhiyun oldStretch = g->stretch;
3364*4882a593Smuzhiyun user_params[drive] = *g;
3365*4882a593Smuzhiyun if (buffer_drive == drive)
3366*4882a593Smuzhiyun SUPBOUND(buffer_max, user_params[drive].sect);
3367*4882a593Smuzhiyun current_type[drive] = &user_params[drive];
3368*4882a593Smuzhiyun floppy_sizes[drive] = user_params[drive].size;
3369*4882a593Smuzhiyun if (cmd == FDDEFPRM)
3370*4882a593Smuzhiyun drive_state[current_drive].keep_data = -1;
3371*4882a593Smuzhiyun else
3372*4882a593Smuzhiyun drive_state[current_drive].keep_data = 1;
3373*4882a593Smuzhiyun /* invalidation. Invalidate only when needed, i.e.
3374*4882a593Smuzhiyun * when there are already sectors in the buffer cache
3375*4882a593Smuzhiyun * whose number will change. This is useful, because
3376*4882a593Smuzhiyun * mtools often changes the geometry of the disk after
3377*4882a593Smuzhiyun * looking at the boot block */
3378*4882a593Smuzhiyun if (drive_state[current_drive].maxblock > user_params[drive].sect ||
3379*4882a593Smuzhiyun drive_state[current_drive].maxtrack ||
3380*4882a593Smuzhiyun ((user_params[drive].sect ^ oldStretch) &
3381*4882a593Smuzhiyun (FD_SWAPSIDES | FD_SECTBASEMASK)))
3382*4882a593Smuzhiyun invalidate_drive(bdev);
3383*4882a593Smuzhiyun else
3384*4882a593Smuzhiyun process_fd_request();
3385*4882a593Smuzhiyun }
3386*4882a593Smuzhiyun return 0;
3387*4882a593Smuzhiyun }
3388*4882a593Smuzhiyun
3389*4882a593Smuzhiyun /* handle obsolete ioctl's */
3390*4882a593Smuzhiyun static unsigned int ioctl_table[] = {
3391*4882a593Smuzhiyun FDCLRPRM,
3392*4882a593Smuzhiyun FDSETPRM,
3393*4882a593Smuzhiyun FDDEFPRM,
3394*4882a593Smuzhiyun FDGETPRM,
3395*4882a593Smuzhiyun FDMSGON,
3396*4882a593Smuzhiyun FDMSGOFF,
3397*4882a593Smuzhiyun FDFMTBEG,
3398*4882a593Smuzhiyun FDFMTTRK,
3399*4882a593Smuzhiyun FDFMTEND,
3400*4882a593Smuzhiyun FDSETEMSGTRESH,
3401*4882a593Smuzhiyun FDFLUSH,
3402*4882a593Smuzhiyun FDSETMAXERRS,
3403*4882a593Smuzhiyun FDGETMAXERRS,
3404*4882a593Smuzhiyun FDGETDRVTYP,
3405*4882a593Smuzhiyun FDSETDRVPRM,
3406*4882a593Smuzhiyun FDGETDRVPRM,
3407*4882a593Smuzhiyun FDGETDRVSTAT,
3408*4882a593Smuzhiyun FDPOLLDRVSTAT,
3409*4882a593Smuzhiyun FDRESET,
3410*4882a593Smuzhiyun FDGETFDCSTAT,
3411*4882a593Smuzhiyun FDWERRORCLR,
3412*4882a593Smuzhiyun FDWERRORGET,
3413*4882a593Smuzhiyun FDRAWCMD,
3414*4882a593Smuzhiyun FDEJECT,
3415*4882a593Smuzhiyun FDTWADDLE
3416*4882a593Smuzhiyun };
3417*4882a593Smuzhiyun
normalize_ioctl(unsigned int * cmd,int * size)3418*4882a593Smuzhiyun static int normalize_ioctl(unsigned int *cmd, int *size)
3419*4882a593Smuzhiyun {
3420*4882a593Smuzhiyun int i;
3421*4882a593Smuzhiyun
3422*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(ioctl_table); i++) {
3423*4882a593Smuzhiyun if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)) {
3424*4882a593Smuzhiyun *size = _IOC_SIZE(*cmd);
3425*4882a593Smuzhiyun *cmd = ioctl_table[i];
3426*4882a593Smuzhiyun if (*size > _IOC_SIZE(*cmd)) {
3427*4882a593Smuzhiyun pr_info("ioctl not yet supported\n");
3428*4882a593Smuzhiyun return -EFAULT;
3429*4882a593Smuzhiyun }
3430*4882a593Smuzhiyun return 0;
3431*4882a593Smuzhiyun }
3432*4882a593Smuzhiyun }
3433*4882a593Smuzhiyun return -EINVAL;
3434*4882a593Smuzhiyun }
3435*4882a593Smuzhiyun
get_floppy_geometry(int drive,int type,struct floppy_struct ** g)3436*4882a593Smuzhiyun static int get_floppy_geometry(int drive, int type, struct floppy_struct **g)
3437*4882a593Smuzhiyun {
3438*4882a593Smuzhiyun if (type)
3439*4882a593Smuzhiyun *g = &floppy_type[type];
3440*4882a593Smuzhiyun else {
3441*4882a593Smuzhiyun if (lock_fdc(drive))
3442*4882a593Smuzhiyun return -EINTR;
3443*4882a593Smuzhiyun if (poll_drive(false, 0) == -EINTR)
3444*4882a593Smuzhiyun return -EINTR;
3445*4882a593Smuzhiyun process_fd_request();
3446*4882a593Smuzhiyun *g = current_type[drive];
3447*4882a593Smuzhiyun }
3448*4882a593Smuzhiyun if (!*g)
3449*4882a593Smuzhiyun return -ENODEV;
3450*4882a593Smuzhiyun return 0;
3451*4882a593Smuzhiyun }
3452*4882a593Smuzhiyun
fd_getgeo(struct block_device * bdev,struct hd_geometry * geo)3453*4882a593Smuzhiyun static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
3454*4882a593Smuzhiyun {
3455*4882a593Smuzhiyun int drive = (long)bdev->bd_disk->private_data;
3456*4882a593Smuzhiyun int type = ITYPE(drive_state[drive].fd_device);
3457*4882a593Smuzhiyun struct floppy_struct *g;
3458*4882a593Smuzhiyun int ret;
3459*4882a593Smuzhiyun
3460*4882a593Smuzhiyun ret = get_floppy_geometry(drive, type, &g);
3461*4882a593Smuzhiyun if (ret)
3462*4882a593Smuzhiyun return ret;
3463*4882a593Smuzhiyun
3464*4882a593Smuzhiyun geo->heads = g->head;
3465*4882a593Smuzhiyun geo->sectors = g->sect;
3466*4882a593Smuzhiyun geo->cylinders = g->track;
3467*4882a593Smuzhiyun return 0;
3468*4882a593Smuzhiyun }
3469*4882a593Smuzhiyun
valid_floppy_drive_params(const short autodetect[FD_AUTODETECT_SIZE],int native_format)3470*4882a593Smuzhiyun static bool valid_floppy_drive_params(const short autodetect[FD_AUTODETECT_SIZE],
3471*4882a593Smuzhiyun int native_format)
3472*4882a593Smuzhiyun {
3473*4882a593Smuzhiyun size_t floppy_type_size = ARRAY_SIZE(floppy_type);
3474*4882a593Smuzhiyun size_t i = 0;
3475*4882a593Smuzhiyun
3476*4882a593Smuzhiyun for (i = 0; i < FD_AUTODETECT_SIZE; ++i) {
3477*4882a593Smuzhiyun if (autodetect[i] < 0 ||
3478*4882a593Smuzhiyun autodetect[i] >= floppy_type_size)
3479*4882a593Smuzhiyun return false;
3480*4882a593Smuzhiyun }
3481*4882a593Smuzhiyun
3482*4882a593Smuzhiyun if (native_format < 0 || native_format >= floppy_type_size)
3483*4882a593Smuzhiyun return false;
3484*4882a593Smuzhiyun
3485*4882a593Smuzhiyun return true;
3486*4882a593Smuzhiyun }
3487*4882a593Smuzhiyun
fd_locked_ioctl(struct block_device * bdev,fmode_t mode,unsigned int cmd,unsigned long param)3488*4882a593Smuzhiyun static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
3489*4882a593Smuzhiyun unsigned long param)
3490*4882a593Smuzhiyun {
3491*4882a593Smuzhiyun int drive = (long)bdev->bd_disk->private_data;
3492*4882a593Smuzhiyun int type = ITYPE(drive_state[drive].fd_device);
3493*4882a593Smuzhiyun int ret;
3494*4882a593Smuzhiyun int size;
3495*4882a593Smuzhiyun union inparam {
3496*4882a593Smuzhiyun struct floppy_struct g; /* geometry */
3497*4882a593Smuzhiyun struct format_descr f;
3498*4882a593Smuzhiyun struct floppy_max_errors max_errors;
3499*4882a593Smuzhiyun struct floppy_drive_params dp;
3500*4882a593Smuzhiyun } inparam; /* parameters coming from user space */
3501*4882a593Smuzhiyun const void *outparam; /* parameters passed back to user space */
3502*4882a593Smuzhiyun
3503*4882a593Smuzhiyun /* convert compatibility eject ioctls into floppy eject ioctl.
3504*4882a593Smuzhiyun * We do this in order to provide a means to eject floppy disks before
3505*4882a593Smuzhiyun * installing the new fdutils package */
3506*4882a593Smuzhiyun if (cmd == CDROMEJECT || /* CD-ROM eject */
3507*4882a593Smuzhiyun cmd == 0x6470) { /* SunOS floppy eject */
3508*4882a593Smuzhiyun DPRINT("obsolete eject ioctl\n");
3509*4882a593Smuzhiyun DPRINT("please use floppycontrol --eject\n");
3510*4882a593Smuzhiyun cmd = FDEJECT;
3511*4882a593Smuzhiyun }
3512*4882a593Smuzhiyun
3513*4882a593Smuzhiyun if (!((cmd & 0xff00) == 0x0200))
3514*4882a593Smuzhiyun return -EINVAL;
3515*4882a593Smuzhiyun
3516*4882a593Smuzhiyun /* convert the old style command into a new style command */
3517*4882a593Smuzhiyun ret = normalize_ioctl(&cmd, &size);
3518*4882a593Smuzhiyun if (ret)
3519*4882a593Smuzhiyun return ret;
3520*4882a593Smuzhiyun
3521*4882a593Smuzhiyun /* permission checks */
3522*4882a593Smuzhiyun if (((cmd & 0x40) && !(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL))) ||
3523*4882a593Smuzhiyun ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
3524*4882a593Smuzhiyun return -EPERM;
3525*4882a593Smuzhiyun
3526*4882a593Smuzhiyun if (WARN_ON(size < 0 || size > sizeof(inparam)))
3527*4882a593Smuzhiyun return -EINVAL;
3528*4882a593Smuzhiyun
3529*4882a593Smuzhiyun /* copyin */
3530*4882a593Smuzhiyun memset(&inparam, 0, sizeof(inparam));
3531*4882a593Smuzhiyun if (_IOC_DIR(cmd) & _IOC_WRITE) {
3532*4882a593Smuzhiyun ret = fd_copyin((void __user *)param, &inparam, size);
3533*4882a593Smuzhiyun if (ret)
3534*4882a593Smuzhiyun return ret;
3535*4882a593Smuzhiyun }
3536*4882a593Smuzhiyun
3537*4882a593Smuzhiyun switch (cmd) {
3538*4882a593Smuzhiyun case FDEJECT:
3539*4882a593Smuzhiyun if (drive_state[drive].fd_ref != 1)
3540*4882a593Smuzhiyun /* somebody else has this drive open */
3541*4882a593Smuzhiyun return -EBUSY;
3542*4882a593Smuzhiyun if (lock_fdc(drive))
3543*4882a593Smuzhiyun return -EINTR;
3544*4882a593Smuzhiyun
3545*4882a593Smuzhiyun /* do the actual eject. Fails on
3546*4882a593Smuzhiyun * non-Sparc architectures */
3547*4882a593Smuzhiyun ret = fd_eject(UNIT(drive));
3548*4882a593Smuzhiyun
3549*4882a593Smuzhiyun set_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags);
3550*4882a593Smuzhiyun set_bit(FD_VERIFY_BIT, &drive_state[drive].flags);
3551*4882a593Smuzhiyun process_fd_request();
3552*4882a593Smuzhiyun return ret;
3553*4882a593Smuzhiyun case FDCLRPRM:
3554*4882a593Smuzhiyun if (lock_fdc(drive))
3555*4882a593Smuzhiyun return -EINTR;
3556*4882a593Smuzhiyun current_type[drive] = NULL;
3557*4882a593Smuzhiyun floppy_sizes[drive] = MAX_DISK_SIZE << 1;
3558*4882a593Smuzhiyun drive_state[drive].keep_data = 0;
3559*4882a593Smuzhiyun return invalidate_drive(bdev);
3560*4882a593Smuzhiyun case FDSETPRM:
3561*4882a593Smuzhiyun case FDDEFPRM:
3562*4882a593Smuzhiyun return set_geometry(cmd, &inparam.g, drive, type, bdev);
3563*4882a593Smuzhiyun case FDGETPRM:
3564*4882a593Smuzhiyun ret = get_floppy_geometry(drive, type,
3565*4882a593Smuzhiyun (struct floppy_struct **)&outparam);
3566*4882a593Smuzhiyun if (ret)
3567*4882a593Smuzhiyun return ret;
3568*4882a593Smuzhiyun memcpy(&inparam.g, outparam,
3569*4882a593Smuzhiyun offsetof(struct floppy_struct, name));
3570*4882a593Smuzhiyun outparam = &inparam.g;
3571*4882a593Smuzhiyun break;
3572*4882a593Smuzhiyun case FDMSGON:
3573*4882a593Smuzhiyun drive_params[drive].flags |= FTD_MSG;
3574*4882a593Smuzhiyun return 0;
3575*4882a593Smuzhiyun case FDMSGOFF:
3576*4882a593Smuzhiyun drive_params[drive].flags &= ~FTD_MSG;
3577*4882a593Smuzhiyun return 0;
3578*4882a593Smuzhiyun case FDFMTBEG:
3579*4882a593Smuzhiyun if (lock_fdc(drive))
3580*4882a593Smuzhiyun return -EINTR;
3581*4882a593Smuzhiyun if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
3582*4882a593Smuzhiyun return -EINTR;
3583*4882a593Smuzhiyun ret = drive_state[drive].flags;
3584*4882a593Smuzhiyun process_fd_request();
3585*4882a593Smuzhiyun if (ret & FD_VERIFY)
3586*4882a593Smuzhiyun return -ENODEV;
3587*4882a593Smuzhiyun if (!(ret & FD_DISK_WRITABLE))
3588*4882a593Smuzhiyun return -EROFS;
3589*4882a593Smuzhiyun return 0;
3590*4882a593Smuzhiyun case FDFMTTRK:
3591*4882a593Smuzhiyun if (drive_state[drive].fd_ref != 1)
3592*4882a593Smuzhiyun return -EBUSY;
3593*4882a593Smuzhiyun return do_format(drive, &inparam.f);
3594*4882a593Smuzhiyun case FDFMTEND:
3595*4882a593Smuzhiyun case FDFLUSH:
3596*4882a593Smuzhiyun if (lock_fdc(drive))
3597*4882a593Smuzhiyun return -EINTR;
3598*4882a593Smuzhiyun return invalidate_drive(bdev);
3599*4882a593Smuzhiyun case FDSETEMSGTRESH:
3600*4882a593Smuzhiyun drive_params[drive].max_errors.reporting = (unsigned short)(param & 0x0f);
3601*4882a593Smuzhiyun return 0;
3602*4882a593Smuzhiyun case FDGETMAXERRS:
3603*4882a593Smuzhiyun outparam = &drive_params[drive].max_errors;
3604*4882a593Smuzhiyun break;
3605*4882a593Smuzhiyun case FDSETMAXERRS:
3606*4882a593Smuzhiyun drive_params[drive].max_errors = inparam.max_errors;
3607*4882a593Smuzhiyun break;
3608*4882a593Smuzhiyun case FDGETDRVTYP:
3609*4882a593Smuzhiyun outparam = drive_name(type, drive);
3610*4882a593Smuzhiyun SUPBOUND(size, strlen((const char *)outparam) + 1);
3611*4882a593Smuzhiyun break;
3612*4882a593Smuzhiyun case FDSETDRVPRM:
3613*4882a593Smuzhiyun if (!valid_floppy_drive_params(inparam.dp.autodetect,
3614*4882a593Smuzhiyun inparam.dp.native_format))
3615*4882a593Smuzhiyun return -EINVAL;
3616*4882a593Smuzhiyun drive_params[drive] = inparam.dp;
3617*4882a593Smuzhiyun break;
3618*4882a593Smuzhiyun case FDGETDRVPRM:
3619*4882a593Smuzhiyun outparam = &drive_params[drive];
3620*4882a593Smuzhiyun break;
3621*4882a593Smuzhiyun case FDPOLLDRVSTAT:
3622*4882a593Smuzhiyun if (lock_fdc(drive))
3623*4882a593Smuzhiyun return -EINTR;
3624*4882a593Smuzhiyun if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
3625*4882a593Smuzhiyun return -EINTR;
3626*4882a593Smuzhiyun process_fd_request();
3627*4882a593Smuzhiyun fallthrough;
3628*4882a593Smuzhiyun case FDGETDRVSTAT:
3629*4882a593Smuzhiyun outparam = &drive_state[drive];
3630*4882a593Smuzhiyun break;
3631*4882a593Smuzhiyun case FDRESET:
3632*4882a593Smuzhiyun return user_reset_fdc(drive, (int)param, true);
3633*4882a593Smuzhiyun case FDGETFDCSTAT:
3634*4882a593Smuzhiyun outparam = &fdc_state[FDC(drive)];
3635*4882a593Smuzhiyun break;
3636*4882a593Smuzhiyun case FDWERRORCLR:
3637*4882a593Smuzhiyun memset(&write_errors[drive], 0, sizeof(write_errors[drive]));
3638*4882a593Smuzhiyun return 0;
3639*4882a593Smuzhiyun case FDWERRORGET:
3640*4882a593Smuzhiyun outparam = &write_errors[drive];
3641*4882a593Smuzhiyun break;
3642*4882a593Smuzhiyun case FDRAWCMD:
3643*4882a593Smuzhiyun return floppy_raw_cmd_ioctl(type, drive, cmd, (void __user *)param);
3644*4882a593Smuzhiyun case FDTWADDLE:
3645*4882a593Smuzhiyun if (lock_fdc(drive))
3646*4882a593Smuzhiyun return -EINTR;
3647*4882a593Smuzhiyun twaddle(current_fdc, current_drive);
3648*4882a593Smuzhiyun process_fd_request();
3649*4882a593Smuzhiyun return 0;
3650*4882a593Smuzhiyun default:
3651*4882a593Smuzhiyun return -EINVAL;
3652*4882a593Smuzhiyun }
3653*4882a593Smuzhiyun
3654*4882a593Smuzhiyun if (_IOC_DIR(cmd) & _IOC_READ)
3655*4882a593Smuzhiyun return fd_copyout((void __user *)param, outparam, size);
3656*4882a593Smuzhiyun
3657*4882a593Smuzhiyun return 0;
3658*4882a593Smuzhiyun }
3659*4882a593Smuzhiyun
fd_ioctl(struct block_device * bdev,fmode_t mode,unsigned int cmd,unsigned long param)3660*4882a593Smuzhiyun static int fd_ioctl(struct block_device *bdev, fmode_t mode,
3661*4882a593Smuzhiyun unsigned int cmd, unsigned long param)
3662*4882a593Smuzhiyun {
3663*4882a593Smuzhiyun int ret;
3664*4882a593Smuzhiyun
3665*4882a593Smuzhiyun mutex_lock(&floppy_mutex);
3666*4882a593Smuzhiyun ret = fd_locked_ioctl(bdev, mode, cmd, param);
3667*4882a593Smuzhiyun mutex_unlock(&floppy_mutex);
3668*4882a593Smuzhiyun
3669*4882a593Smuzhiyun return ret;
3670*4882a593Smuzhiyun }
3671*4882a593Smuzhiyun
3672*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
3673*4882a593Smuzhiyun
3674*4882a593Smuzhiyun struct compat_floppy_drive_params {
3675*4882a593Smuzhiyun char cmos;
3676*4882a593Smuzhiyun compat_ulong_t max_dtr;
3677*4882a593Smuzhiyun compat_ulong_t hlt;
3678*4882a593Smuzhiyun compat_ulong_t hut;
3679*4882a593Smuzhiyun compat_ulong_t srt;
3680*4882a593Smuzhiyun compat_ulong_t spinup;
3681*4882a593Smuzhiyun compat_ulong_t spindown;
3682*4882a593Smuzhiyun unsigned char spindown_offset;
3683*4882a593Smuzhiyun unsigned char select_delay;
3684*4882a593Smuzhiyun unsigned char rps;
3685*4882a593Smuzhiyun unsigned char tracks;
3686*4882a593Smuzhiyun compat_ulong_t timeout;
3687*4882a593Smuzhiyun unsigned char interleave_sect;
3688*4882a593Smuzhiyun struct floppy_max_errors max_errors;
3689*4882a593Smuzhiyun char flags;
3690*4882a593Smuzhiyun char read_track;
3691*4882a593Smuzhiyun short autodetect[FD_AUTODETECT_SIZE];
3692*4882a593Smuzhiyun compat_int_t checkfreq;
3693*4882a593Smuzhiyun compat_int_t native_format;
3694*4882a593Smuzhiyun };
3695*4882a593Smuzhiyun
3696*4882a593Smuzhiyun struct compat_floppy_drive_struct {
3697*4882a593Smuzhiyun signed char flags;
3698*4882a593Smuzhiyun compat_ulong_t spinup_date;
3699*4882a593Smuzhiyun compat_ulong_t select_date;
3700*4882a593Smuzhiyun compat_ulong_t first_read_date;
3701*4882a593Smuzhiyun short probed_format;
3702*4882a593Smuzhiyun short track;
3703*4882a593Smuzhiyun short maxblock;
3704*4882a593Smuzhiyun short maxtrack;
3705*4882a593Smuzhiyun compat_int_t generation;
3706*4882a593Smuzhiyun compat_int_t keep_data;
3707*4882a593Smuzhiyun compat_int_t fd_ref;
3708*4882a593Smuzhiyun compat_int_t fd_device;
3709*4882a593Smuzhiyun compat_int_t last_checked;
3710*4882a593Smuzhiyun compat_caddr_t dmabuf;
3711*4882a593Smuzhiyun compat_int_t bufblocks;
3712*4882a593Smuzhiyun };
3713*4882a593Smuzhiyun
3714*4882a593Smuzhiyun struct compat_floppy_fdc_state {
3715*4882a593Smuzhiyun compat_int_t spec1;
3716*4882a593Smuzhiyun compat_int_t spec2;
3717*4882a593Smuzhiyun compat_int_t dtr;
3718*4882a593Smuzhiyun unsigned char version;
3719*4882a593Smuzhiyun unsigned char dor;
3720*4882a593Smuzhiyun compat_ulong_t address;
3721*4882a593Smuzhiyun unsigned int rawcmd:2;
3722*4882a593Smuzhiyun unsigned int reset:1;
3723*4882a593Smuzhiyun unsigned int need_configure:1;
3724*4882a593Smuzhiyun unsigned int perp_mode:2;
3725*4882a593Smuzhiyun unsigned int has_fifo:1;
3726*4882a593Smuzhiyun unsigned int driver_version;
3727*4882a593Smuzhiyun unsigned char track[4];
3728*4882a593Smuzhiyun };
3729*4882a593Smuzhiyun
3730*4882a593Smuzhiyun struct compat_floppy_write_errors {
3731*4882a593Smuzhiyun unsigned int write_errors;
3732*4882a593Smuzhiyun compat_ulong_t first_error_sector;
3733*4882a593Smuzhiyun compat_int_t first_error_generation;
3734*4882a593Smuzhiyun compat_ulong_t last_error_sector;
3735*4882a593Smuzhiyun compat_int_t last_error_generation;
3736*4882a593Smuzhiyun compat_uint_t badness;
3737*4882a593Smuzhiyun };
3738*4882a593Smuzhiyun
3739*4882a593Smuzhiyun #define FDSETPRM32 _IOW(2, 0x42, struct compat_floppy_struct)
3740*4882a593Smuzhiyun #define FDDEFPRM32 _IOW(2, 0x43, struct compat_floppy_struct)
3741*4882a593Smuzhiyun #define FDSETDRVPRM32 _IOW(2, 0x90, struct compat_floppy_drive_params)
3742*4882a593Smuzhiyun #define FDGETDRVPRM32 _IOR(2, 0x11, struct compat_floppy_drive_params)
3743*4882a593Smuzhiyun #define FDGETDRVSTAT32 _IOR(2, 0x12, struct compat_floppy_drive_struct)
3744*4882a593Smuzhiyun #define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct compat_floppy_drive_struct)
3745*4882a593Smuzhiyun #define FDGETFDCSTAT32 _IOR(2, 0x15, struct compat_floppy_fdc_state)
3746*4882a593Smuzhiyun #define FDWERRORGET32 _IOR(2, 0x17, struct compat_floppy_write_errors)
3747*4882a593Smuzhiyun
compat_set_geometry(struct block_device * bdev,fmode_t mode,unsigned int cmd,struct compat_floppy_struct __user * arg)3748*4882a593Smuzhiyun static int compat_set_geometry(struct block_device *bdev, fmode_t mode, unsigned int cmd,
3749*4882a593Smuzhiyun struct compat_floppy_struct __user *arg)
3750*4882a593Smuzhiyun {
3751*4882a593Smuzhiyun struct floppy_struct v;
3752*4882a593Smuzhiyun int drive, type;
3753*4882a593Smuzhiyun int err;
3754*4882a593Smuzhiyun
3755*4882a593Smuzhiyun BUILD_BUG_ON(offsetof(struct floppy_struct, name) !=
3756*4882a593Smuzhiyun offsetof(struct compat_floppy_struct, name));
3757*4882a593Smuzhiyun
3758*4882a593Smuzhiyun if (!(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL)))
3759*4882a593Smuzhiyun return -EPERM;
3760*4882a593Smuzhiyun
3761*4882a593Smuzhiyun memset(&v, 0, sizeof(struct floppy_struct));
3762*4882a593Smuzhiyun if (copy_from_user(&v, arg, offsetof(struct floppy_struct, name)))
3763*4882a593Smuzhiyun return -EFAULT;
3764*4882a593Smuzhiyun
3765*4882a593Smuzhiyun mutex_lock(&floppy_mutex);
3766*4882a593Smuzhiyun drive = (long)bdev->bd_disk->private_data;
3767*4882a593Smuzhiyun type = ITYPE(drive_state[drive].fd_device);
3768*4882a593Smuzhiyun err = set_geometry(cmd == FDSETPRM32 ? FDSETPRM : FDDEFPRM,
3769*4882a593Smuzhiyun &v, drive, type, bdev);
3770*4882a593Smuzhiyun mutex_unlock(&floppy_mutex);
3771*4882a593Smuzhiyun return err;
3772*4882a593Smuzhiyun }
3773*4882a593Smuzhiyun
compat_get_prm(int drive,struct compat_floppy_struct __user * arg)3774*4882a593Smuzhiyun static int compat_get_prm(int drive,
3775*4882a593Smuzhiyun struct compat_floppy_struct __user *arg)
3776*4882a593Smuzhiyun {
3777*4882a593Smuzhiyun struct compat_floppy_struct v;
3778*4882a593Smuzhiyun struct floppy_struct *p;
3779*4882a593Smuzhiyun int err;
3780*4882a593Smuzhiyun
3781*4882a593Smuzhiyun memset(&v, 0, sizeof(v));
3782*4882a593Smuzhiyun mutex_lock(&floppy_mutex);
3783*4882a593Smuzhiyun err = get_floppy_geometry(drive, ITYPE(drive_state[drive].fd_device),
3784*4882a593Smuzhiyun &p);
3785*4882a593Smuzhiyun if (err) {
3786*4882a593Smuzhiyun mutex_unlock(&floppy_mutex);
3787*4882a593Smuzhiyun return err;
3788*4882a593Smuzhiyun }
3789*4882a593Smuzhiyun memcpy(&v, p, offsetof(struct floppy_struct, name));
3790*4882a593Smuzhiyun mutex_unlock(&floppy_mutex);
3791*4882a593Smuzhiyun if (copy_to_user(arg, &v, sizeof(struct compat_floppy_struct)))
3792*4882a593Smuzhiyun return -EFAULT;
3793*4882a593Smuzhiyun return 0;
3794*4882a593Smuzhiyun }
3795*4882a593Smuzhiyun
compat_setdrvprm(int drive,struct compat_floppy_drive_params __user * arg)3796*4882a593Smuzhiyun static int compat_setdrvprm(int drive,
3797*4882a593Smuzhiyun struct compat_floppy_drive_params __user *arg)
3798*4882a593Smuzhiyun {
3799*4882a593Smuzhiyun struct compat_floppy_drive_params v;
3800*4882a593Smuzhiyun
3801*4882a593Smuzhiyun if (!capable(CAP_SYS_ADMIN))
3802*4882a593Smuzhiyun return -EPERM;
3803*4882a593Smuzhiyun if (copy_from_user(&v, arg, sizeof(struct compat_floppy_drive_params)))
3804*4882a593Smuzhiyun return -EFAULT;
3805*4882a593Smuzhiyun if (!valid_floppy_drive_params(v.autodetect, v.native_format))
3806*4882a593Smuzhiyun return -EINVAL;
3807*4882a593Smuzhiyun mutex_lock(&floppy_mutex);
3808*4882a593Smuzhiyun drive_params[drive].cmos = v.cmos;
3809*4882a593Smuzhiyun drive_params[drive].max_dtr = v.max_dtr;
3810*4882a593Smuzhiyun drive_params[drive].hlt = v.hlt;
3811*4882a593Smuzhiyun drive_params[drive].hut = v.hut;
3812*4882a593Smuzhiyun drive_params[drive].srt = v.srt;
3813*4882a593Smuzhiyun drive_params[drive].spinup = v.spinup;
3814*4882a593Smuzhiyun drive_params[drive].spindown = v.spindown;
3815*4882a593Smuzhiyun drive_params[drive].spindown_offset = v.spindown_offset;
3816*4882a593Smuzhiyun drive_params[drive].select_delay = v.select_delay;
3817*4882a593Smuzhiyun drive_params[drive].rps = v.rps;
3818*4882a593Smuzhiyun drive_params[drive].tracks = v.tracks;
3819*4882a593Smuzhiyun drive_params[drive].timeout = v.timeout;
3820*4882a593Smuzhiyun drive_params[drive].interleave_sect = v.interleave_sect;
3821*4882a593Smuzhiyun drive_params[drive].max_errors = v.max_errors;
3822*4882a593Smuzhiyun drive_params[drive].flags = v.flags;
3823*4882a593Smuzhiyun drive_params[drive].read_track = v.read_track;
3824*4882a593Smuzhiyun memcpy(drive_params[drive].autodetect, v.autodetect,
3825*4882a593Smuzhiyun sizeof(v.autodetect));
3826*4882a593Smuzhiyun drive_params[drive].checkfreq = v.checkfreq;
3827*4882a593Smuzhiyun drive_params[drive].native_format = v.native_format;
3828*4882a593Smuzhiyun mutex_unlock(&floppy_mutex);
3829*4882a593Smuzhiyun return 0;
3830*4882a593Smuzhiyun }
3831*4882a593Smuzhiyun
compat_getdrvprm(int drive,struct compat_floppy_drive_params __user * arg)3832*4882a593Smuzhiyun static int compat_getdrvprm(int drive,
3833*4882a593Smuzhiyun struct compat_floppy_drive_params __user *arg)
3834*4882a593Smuzhiyun {
3835*4882a593Smuzhiyun struct compat_floppy_drive_params v;
3836*4882a593Smuzhiyun
3837*4882a593Smuzhiyun memset(&v, 0, sizeof(struct compat_floppy_drive_params));
3838*4882a593Smuzhiyun mutex_lock(&floppy_mutex);
3839*4882a593Smuzhiyun v.cmos = drive_params[drive].cmos;
3840*4882a593Smuzhiyun v.max_dtr = drive_params[drive].max_dtr;
3841*4882a593Smuzhiyun v.hlt = drive_params[drive].hlt;
3842*4882a593Smuzhiyun v.hut = drive_params[drive].hut;
3843*4882a593Smuzhiyun v.srt = drive_params[drive].srt;
3844*4882a593Smuzhiyun v.spinup = drive_params[drive].spinup;
3845*4882a593Smuzhiyun v.spindown = drive_params[drive].spindown;
3846*4882a593Smuzhiyun v.spindown_offset = drive_params[drive].spindown_offset;
3847*4882a593Smuzhiyun v.select_delay = drive_params[drive].select_delay;
3848*4882a593Smuzhiyun v.rps = drive_params[drive].rps;
3849*4882a593Smuzhiyun v.tracks = drive_params[drive].tracks;
3850*4882a593Smuzhiyun v.timeout = drive_params[drive].timeout;
3851*4882a593Smuzhiyun v.interleave_sect = drive_params[drive].interleave_sect;
3852*4882a593Smuzhiyun v.max_errors = drive_params[drive].max_errors;
3853*4882a593Smuzhiyun v.flags = drive_params[drive].flags;
3854*4882a593Smuzhiyun v.read_track = drive_params[drive].read_track;
3855*4882a593Smuzhiyun memcpy(v.autodetect, drive_params[drive].autodetect,
3856*4882a593Smuzhiyun sizeof(v.autodetect));
3857*4882a593Smuzhiyun v.checkfreq = drive_params[drive].checkfreq;
3858*4882a593Smuzhiyun v.native_format = drive_params[drive].native_format;
3859*4882a593Smuzhiyun mutex_unlock(&floppy_mutex);
3860*4882a593Smuzhiyun
3861*4882a593Smuzhiyun if (copy_to_user(arg, &v, sizeof(struct compat_floppy_drive_params)))
3862*4882a593Smuzhiyun return -EFAULT;
3863*4882a593Smuzhiyun return 0;
3864*4882a593Smuzhiyun }
3865*4882a593Smuzhiyun
compat_getdrvstat(int drive,bool poll,struct compat_floppy_drive_struct __user * arg)3866*4882a593Smuzhiyun static int compat_getdrvstat(int drive, bool poll,
3867*4882a593Smuzhiyun struct compat_floppy_drive_struct __user *arg)
3868*4882a593Smuzhiyun {
3869*4882a593Smuzhiyun struct compat_floppy_drive_struct v;
3870*4882a593Smuzhiyun
3871*4882a593Smuzhiyun memset(&v, 0, sizeof(struct compat_floppy_drive_struct));
3872*4882a593Smuzhiyun mutex_lock(&floppy_mutex);
3873*4882a593Smuzhiyun
3874*4882a593Smuzhiyun if (poll) {
3875*4882a593Smuzhiyun if (lock_fdc(drive))
3876*4882a593Smuzhiyun goto Eintr;
3877*4882a593Smuzhiyun if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
3878*4882a593Smuzhiyun goto Eintr;
3879*4882a593Smuzhiyun process_fd_request();
3880*4882a593Smuzhiyun }
3881*4882a593Smuzhiyun v.spinup_date = drive_state[drive].spinup_date;
3882*4882a593Smuzhiyun v.select_date = drive_state[drive].select_date;
3883*4882a593Smuzhiyun v.first_read_date = drive_state[drive].first_read_date;
3884*4882a593Smuzhiyun v.probed_format = drive_state[drive].probed_format;
3885*4882a593Smuzhiyun v.track = drive_state[drive].track;
3886*4882a593Smuzhiyun v.maxblock = drive_state[drive].maxblock;
3887*4882a593Smuzhiyun v.maxtrack = drive_state[drive].maxtrack;
3888*4882a593Smuzhiyun v.generation = drive_state[drive].generation;
3889*4882a593Smuzhiyun v.keep_data = drive_state[drive].keep_data;
3890*4882a593Smuzhiyun v.fd_ref = drive_state[drive].fd_ref;
3891*4882a593Smuzhiyun v.fd_device = drive_state[drive].fd_device;
3892*4882a593Smuzhiyun v.last_checked = drive_state[drive].last_checked;
3893*4882a593Smuzhiyun v.dmabuf = (uintptr_t) drive_state[drive].dmabuf;
3894*4882a593Smuzhiyun v.bufblocks = drive_state[drive].bufblocks;
3895*4882a593Smuzhiyun mutex_unlock(&floppy_mutex);
3896*4882a593Smuzhiyun
3897*4882a593Smuzhiyun if (copy_to_user(arg, &v, sizeof(struct compat_floppy_drive_struct)))
3898*4882a593Smuzhiyun return -EFAULT;
3899*4882a593Smuzhiyun return 0;
3900*4882a593Smuzhiyun Eintr:
3901*4882a593Smuzhiyun mutex_unlock(&floppy_mutex);
3902*4882a593Smuzhiyun return -EINTR;
3903*4882a593Smuzhiyun }
3904*4882a593Smuzhiyun
compat_getfdcstat(int drive,struct compat_floppy_fdc_state __user * arg)3905*4882a593Smuzhiyun static int compat_getfdcstat(int drive,
3906*4882a593Smuzhiyun struct compat_floppy_fdc_state __user *arg)
3907*4882a593Smuzhiyun {
3908*4882a593Smuzhiyun struct compat_floppy_fdc_state v32;
3909*4882a593Smuzhiyun struct floppy_fdc_state v;
3910*4882a593Smuzhiyun
3911*4882a593Smuzhiyun mutex_lock(&floppy_mutex);
3912*4882a593Smuzhiyun v = fdc_state[FDC(drive)];
3913*4882a593Smuzhiyun mutex_unlock(&floppy_mutex);
3914*4882a593Smuzhiyun
3915*4882a593Smuzhiyun memset(&v32, 0, sizeof(struct compat_floppy_fdc_state));
3916*4882a593Smuzhiyun v32.spec1 = v.spec1;
3917*4882a593Smuzhiyun v32.spec2 = v.spec2;
3918*4882a593Smuzhiyun v32.dtr = v.dtr;
3919*4882a593Smuzhiyun v32.version = v.version;
3920*4882a593Smuzhiyun v32.dor = v.dor;
3921*4882a593Smuzhiyun v32.address = v.address;
3922*4882a593Smuzhiyun v32.rawcmd = v.rawcmd;
3923*4882a593Smuzhiyun v32.reset = v.reset;
3924*4882a593Smuzhiyun v32.need_configure = v.need_configure;
3925*4882a593Smuzhiyun v32.perp_mode = v.perp_mode;
3926*4882a593Smuzhiyun v32.has_fifo = v.has_fifo;
3927*4882a593Smuzhiyun v32.driver_version = v.driver_version;
3928*4882a593Smuzhiyun memcpy(v32.track, v.track, 4);
3929*4882a593Smuzhiyun if (copy_to_user(arg, &v32, sizeof(struct compat_floppy_fdc_state)))
3930*4882a593Smuzhiyun return -EFAULT;
3931*4882a593Smuzhiyun return 0;
3932*4882a593Smuzhiyun }
3933*4882a593Smuzhiyun
compat_werrorget(int drive,struct compat_floppy_write_errors __user * arg)3934*4882a593Smuzhiyun static int compat_werrorget(int drive,
3935*4882a593Smuzhiyun struct compat_floppy_write_errors __user *arg)
3936*4882a593Smuzhiyun {
3937*4882a593Smuzhiyun struct compat_floppy_write_errors v32;
3938*4882a593Smuzhiyun struct floppy_write_errors v;
3939*4882a593Smuzhiyun
3940*4882a593Smuzhiyun memset(&v32, 0, sizeof(struct compat_floppy_write_errors));
3941*4882a593Smuzhiyun mutex_lock(&floppy_mutex);
3942*4882a593Smuzhiyun v = write_errors[drive];
3943*4882a593Smuzhiyun mutex_unlock(&floppy_mutex);
3944*4882a593Smuzhiyun v32.write_errors = v.write_errors;
3945*4882a593Smuzhiyun v32.first_error_sector = v.first_error_sector;
3946*4882a593Smuzhiyun v32.first_error_generation = v.first_error_generation;
3947*4882a593Smuzhiyun v32.last_error_sector = v.last_error_sector;
3948*4882a593Smuzhiyun v32.last_error_generation = v.last_error_generation;
3949*4882a593Smuzhiyun v32.badness = v.badness;
3950*4882a593Smuzhiyun if (copy_to_user(arg, &v32, sizeof(struct compat_floppy_write_errors)))
3951*4882a593Smuzhiyun return -EFAULT;
3952*4882a593Smuzhiyun return 0;
3953*4882a593Smuzhiyun }
3954*4882a593Smuzhiyun
fd_compat_ioctl(struct block_device * bdev,fmode_t mode,unsigned int cmd,unsigned long param)3955*4882a593Smuzhiyun static int fd_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
3956*4882a593Smuzhiyun unsigned long param)
3957*4882a593Smuzhiyun {
3958*4882a593Smuzhiyun int drive = (long)bdev->bd_disk->private_data;
3959*4882a593Smuzhiyun switch (cmd) {
3960*4882a593Smuzhiyun case CDROMEJECT: /* CD-ROM eject */
3961*4882a593Smuzhiyun case 0x6470: /* SunOS floppy eject */
3962*4882a593Smuzhiyun
3963*4882a593Smuzhiyun case FDMSGON:
3964*4882a593Smuzhiyun case FDMSGOFF:
3965*4882a593Smuzhiyun case FDSETEMSGTRESH:
3966*4882a593Smuzhiyun case FDFLUSH:
3967*4882a593Smuzhiyun case FDWERRORCLR:
3968*4882a593Smuzhiyun case FDEJECT:
3969*4882a593Smuzhiyun case FDCLRPRM:
3970*4882a593Smuzhiyun case FDFMTBEG:
3971*4882a593Smuzhiyun case FDRESET:
3972*4882a593Smuzhiyun case FDTWADDLE:
3973*4882a593Smuzhiyun return fd_ioctl(bdev, mode, cmd, param);
3974*4882a593Smuzhiyun case FDSETMAXERRS:
3975*4882a593Smuzhiyun case FDGETMAXERRS:
3976*4882a593Smuzhiyun case FDGETDRVTYP:
3977*4882a593Smuzhiyun case FDFMTEND:
3978*4882a593Smuzhiyun case FDFMTTRK:
3979*4882a593Smuzhiyun case FDRAWCMD:
3980*4882a593Smuzhiyun return fd_ioctl(bdev, mode, cmd,
3981*4882a593Smuzhiyun (unsigned long)compat_ptr(param));
3982*4882a593Smuzhiyun case FDSETPRM32:
3983*4882a593Smuzhiyun case FDDEFPRM32:
3984*4882a593Smuzhiyun return compat_set_geometry(bdev, mode, cmd, compat_ptr(param));
3985*4882a593Smuzhiyun case FDGETPRM32:
3986*4882a593Smuzhiyun return compat_get_prm(drive, compat_ptr(param));
3987*4882a593Smuzhiyun case FDSETDRVPRM32:
3988*4882a593Smuzhiyun return compat_setdrvprm(drive, compat_ptr(param));
3989*4882a593Smuzhiyun case FDGETDRVPRM32:
3990*4882a593Smuzhiyun return compat_getdrvprm(drive, compat_ptr(param));
3991*4882a593Smuzhiyun case FDPOLLDRVSTAT32:
3992*4882a593Smuzhiyun return compat_getdrvstat(drive, true, compat_ptr(param));
3993*4882a593Smuzhiyun case FDGETDRVSTAT32:
3994*4882a593Smuzhiyun return compat_getdrvstat(drive, false, compat_ptr(param));
3995*4882a593Smuzhiyun case FDGETFDCSTAT32:
3996*4882a593Smuzhiyun return compat_getfdcstat(drive, compat_ptr(param));
3997*4882a593Smuzhiyun case FDWERRORGET32:
3998*4882a593Smuzhiyun return compat_werrorget(drive, compat_ptr(param));
3999*4882a593Smuzhiyun }
4000*4882a593Smuzhiyun return -EINVAL;
4001*4882a593Smuzhiyun }
4002*4882a593Smuzhiyun #endif
4003*4882a593Smuzhiyun
config_types(void)4004*4882a593Smuzhiyun static void __init config_types(void)
4005*4882a593Smuzhiyun {
4006*4882a593Smuzhiyun bool has_drive = false;
4007*4882a593Smuzhiyun int drive;
4008*4882a593Smuzhiyun
4009*4882a593Smuzhiyun /* read drive info out of physical CMOS */
4010*4882a593Smuzhiyun drive = 0;
4011*4882a593Smuzhiyun if (!drive_params[drive].cmos)
4012*4882a593Smuzhiyun drive_params[drive].cmos = FLOPPY0_TYPE;
4013*4882a593Smuzhiyun drive = 1;
4014*4882a593Smuzhiyun if (!drive_params[drive].cmos)
4015*4882a593Smuzhiyun drive_params[drive].cmos = FLOPPY1_TYPE;
4016*4882a593Smuzhiyun
4017*4882a593Smuzhiyun /* FIXME: additional physical CMOS drive detection should go here */
4018*4882a593Smuzhiyun
4019*4882a593Smuzhiyun for (drive = 0; drive < N_DRIVE; drive++) {
4020*4882a593Smuzhiyun unsigned int type = drive_params[drive].cmos;
4021*4882a593Smuzhiyun struct floppy_drive_params *params;
4022*4882a593Smuzhiyun const char *name = NULL;
4023*4882a593Smuzhiyun char temparea[32];
4024*4882a593Smuzhiyun
4025*4882a593Smuzhiyun if (type < ARRAY_SIZE(default_drive_params)) {
4026*4882a593Smuzhiyun params = &default_drive_params[type].params;
4027*4882a593Smuzhiyun if (type) {
4028*4882a593Smuzhiyun name = default_drive_params[type].name;
4029*4882a593Smuzhiyun allowed_drive_mask |= 1 << drive;
4030*4882a593Smuzhiyun } else
4031*4882a593Smuzhiyun allowed_drive_mask &= ~(1 << drive);
4032*4882a593Smuzhiyun } else {
4033*4882a593Smuzhiyun params = &default_drive_params[0].params;
4034*4882a593Smuzhiyun snprintf(temparea, sizeof(temparea),
4035*4882a593Smuzhiyun "unknown type %d (usb?)", type);
4036*4882a593Smuzhiyun name = temparea;
4037*4882a593Smuzhiyun }
4038*4882a593Smuzhiyun if (name) {
4039*4882a593Smuzhiyun const char *prepend;
4040*4882a593Smuzhiyun if (!has_drive) {
4041*4882a593Smuzhiyun prepend = "";
4042*4882a593Smuzhiyun has_drive = true;
4043*4882a593Smuzhiyun pr_info("Floppy drive(s):");
4044*4882a593Smuzhiyun } else {
4045*4882a593Smuzhiyun prepend = ",";
4046*4882a593Smuzhiyun }
4047*4882a593Smuzhiyun
4048*4882a593Smuzhiyun pr_cont("%s fd%d is %s", prepend, drive, name);
4049*4882a593Smuzhiyun }
4050*4882a593Smuzhiyun drive_params[drive] = *params;
4051*4882a593Smuzhiyun }
4052*4882a593Smuzhiyun
4053*4882a593Smuzhiyun if (has_drive)
4054*4882a593Smuzhiyun pr_cont("\n");
4055*4882a593Smuzhiyun }
4056*4882a593Smuzhiyun
floppy_release(struct gendisk * disk,fmode_t mode)4057*4882a593Smuzhiyun static void floppy_release(struct gendisk *disk, fmode_t mode)
4058*4882a593Smuzhiyun {
4059*4882a593Smuzhiyun int drive = (long)disk->private_data;
4060*4882a593Smuzhiyun
4061*4882a593Smuzhiyun mutex_lock(&floppy_mutex);
4062*4882a593Smuzhiyun mutex_lock(&open_lock);
4063*4882a593Smuzhiyun if (!drive_state[drive].fd_ref--) {
4064*4882a593Smuzhiyun DPRINT("floppy_release with fd_ref == 0");
4065*4882a593Smuzhiyun drive_state[drive].fd_ref = 0;
4066*4882a593Smuzhiyun }
4067*4882a593Smuzhiyun if (!drive_state[drive].fd_ref)
4068*4882a593Smuzhiyun opened_bdev[drive] = NULL;
4069*4882a593Smuzhiyun mutex_unlock(&open_lock);
4070*4882a593Smuzhiyun mutex_unlock(&floppy_mutex);
4071*4882a593Smuzhiyun }
4072*4882a593Smuzhiyun
4073*4882a593Smuzhiyun /*
4074*4882a593Smuzhiyun * floppy_open check for aliasing (/dev/fd0 can be the same as
4075*4882a593Smuzhiyun * /dev/PS0 etc), and disallows simultaneous access to the same
4076*4882a593Smuzhiyun * drive with different device numbers.
4077*4882a593Smuzhiyun */
floppy_open(struct block_device * bdev,fmode_t mode)4078*4882a593Smuzhiyun static int floppy_open(struct block_device *bdev, fmode_t mode)
4079*4882a593Smuzhiyun {
4080*4882a593Smuzhiyun int drive = (long)bdev->bd_disk->private_data;
4081*4882a593Smuzhiyun int old_dev, new_dev;
4082*4882a593Smuzhiyun int try;
4083*4882a593Smuzhiyun int res = -EBUSY;
4084*4882a593Smuzhiyun char *tmp;
4085*4882a593Smuzhiyun
4086*4882a593Smuzhiyun mutex_lock(&floppy_mutex);
4087*4882a593Smuzhiyun mutex_lock(&open_lock);
4088*4882a593Smuzhiyun old_dev = drive_state[drive].fd_device;
4089*4882a593Smuzhiyun if (opened_bdev[drive] && opened_bdev[drive] != bdev)
4090*4882a593Smuzhiyun goto out2;
4091*4882a593Smuzhiyun
4092*4882a593Smuzhiyun if (!drive_state[drive].fd_ref && (drive_params[drive].flags & FD_BROKEN_DCL)) {
4093*4882a593Smuzhiyun set_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags);
4094*4882a593Smuzhiyun set_bit(FD_VERIFY_BIT, &drive_state[drive].flags);
4095*4882a593Smuzhiyun }
4096*4882a593Smuzhiyun
4097*4882a593Smuzhiyun drive_state[drive].fd_ref++;
4098*4882a593Smuzhiyun
4099*4882a593Smuzhiyun opened_bdev[drive] = bdev;
4100*4882a593Smuzhiyun
4101*4882a593Smuzhiyun res = -ENXIO;
4102*4882a593Smuzhiyun
4103*4882a593Smuzhiyun if (!floppy_track_buffer) {
4104*4882a593Smuzhiyun /* if opening an ED drive, reserve a big buffer,
4105*4882a593Smuzhiyun * else reserve a small one */
4106*4882a593Smuzhiyun if ((drive_params[drive].cmos == 6) || (drive_params[drive].cmos == 5))
4107*4882a593Smuzhiyun try = 64; /* Only 48 actually useful */
4108*4882a593Smuzhiyun else
4109*4882a593Smuzhiyun try = 32; /* Only 24 actually useful */
4110*4882a593Smuzhiyun
4111*4882a593Smuzhiyun tmp = (char *)fd_dma_mem_alloc(1024 * try);
4112*4882a593Smuzhiyun if (!tmp && !floppy_track_buffer) {
4113*4882a593Smuzhiyun try >>= 1; /* buffer only one side */
4114*4882a593Smuzhiyun INFBOUND(try, 16);
4115*4882a593Smuzhiyun tmp = (char *)fd_dma_mem_alloc(1024 * try);
4116*4882a593Smuzhiyun }
4117*4882a593Smuzhiyun if (!tmp && !floppy_track_buffer)
4118*4882a593Smuzhiyun fallback_on_nodma_alloc(&tmp, 2048 * try);
4119*4882a593Smuzhiyun if (!tmp && !floppy_track_buffer) {
4120*4882a593Smuzhiyun DPRINT("Unable to allocate DMA memory\n");
4121*4882a593Smuzhiyun goto out;
4122*4882a593Smuzhiyun }
4123*4882a593Smuzhiyun if (floppy_track_buffer) {
4124*4882a593Smuzhiyun if (tmp)
4125*4882a593Smuzhiyun fd_dma_mem_free((unsigned long)tmp, try * 1024);
4126*4882a593Smuzhiyun } else {
4127*4882a593Smuzhiyun buffer_min = buffer_max = -1;
4128*4882a593Smuzhiyun floppy_track_buffer = tmp;
4129*4882a593Smuzhiyun max_buffer_sectors = try;
4130*4882a593Smuzhiyun }
4131*4882a593Smuzhiyun }
4132*4882a593Smuzhiyun
4133*4882a593Smuzhiyun new_dev = MINOR(bdev->bd_dev);
4134*4882a593Smuzhiyun drive_state[drive].fd_device = new_dev;
4135*4882a593Smuzhiyun set_capacity(disks[drive], floppy_sizes[new_dev]);
4136*4882a593Smuzhiyun if (old_dev != -1 && old_dev != new_dev) {
4137*4882a593Smuzhiyun if (buffer_drive == drive)
4138*4882a593Smuzhiyun buffer_track = -1;
4139*4882a593Smuzhiyun }
4140*4882a593Smuzhiyun
4141*4882a593Smuzhiyun if (fdc_state[FDC(drive)].rawcmd == 1)
4142*4882a593Smuzhiyun fdc_state[FDC(drive)].rawcmd = 2;
4143*4882a593Smuzhiyun
4144*4882a593Smuzhiyun if (!(mode & FMODE_NDELAY)) {
4145*4882a593Smuzhiyun if (mode & (FMODE_READ|FMODE_WRITE)) {
4146*4882a593Smuzhiyun drive_state[drive].last_checked = 0;
4147*4882a593Smuzhiyun clear_bit(FD_OPEN_SHOULD_FAIL_BIT,
4148*4882a593Smuzhiyun &drive_state[drive].flags);
4149*4882a593Smuzhiyun if (bdev_check_media_change(bdev))
4150*4882a593Smuzhiyun floppy_revalidate(bdev->bd_disk);
4151*4882a593Smuzhiyun if (test_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags))
4152*4882a593Smuzhiyun goto out;
4153*4882a593Smuzhiyun if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &drive_state[drive].flags))
4154*4882a593Smuzhiyun goto out;
4155*4882a593Smuzhiyun }
4156*4882a593Smuzhiyun res = -EROFS;
4157*4882a593Smuzhiyun if ((mode & FMODE_WRITE) &&
4158*4882a593Smuzhiyun !test_bit(FD_DISK_WRITABLE_BIT, &drive_state[drive].flags))
4159*4882a593Smuzhiyun goto out;
4160*4882a593Smuzhiyun }
4161*4882a593Smuzhiyun mutex_unlock(&open_lock);
4162*4882a593Smuzhiyun mutex_unlock(&floppy_mutex);
4163*4882a593Smuzhiyun return 0;
4164*4882a593Smuzhiyun out:
4165*4882a593Smuzhiyun drive_state[drive].fd_ref--;
4166*4882a593Smuzhiyun
4167*4882a593Smuzhiyun if (!drive_state[drive].fd_ref)
4168*4882a593Smuzhiyun opened_bdev[drive] = NULL;
4169*4882a593Smuzhiyun out2:
4170*4882a593Smuzhiyun mutex_unlock(&open_lock);
4171*4882a593Smuzhiyun mutex_unlock(&floppy_mutex);
4172*4882a593Smuzhiyun return res;
4173*4882a593Smuzhiyun }
4174*4882a593Smuzhiyun
4175*4882a593Smuzhiyun /*
4176*4882a593Smuzhiyun * Check if the disk has been changed or if a change has been faked.
4177*4882a593Smuzhiyun */
floppy_check_events(struct gendisk * disk,unsigned int clearing)4178*4882a593Smuzhiyun static unsigned int floppy_check_events(struct gendisk *disk,
4179*4882a593Smuzhiyun unsigned int clearing)
4180*4882a593Smuzhiyun {
4181*4882a593Smuzhiyun int drive = (long)disk->private_data;
4182*4882a593Smuzhiyun
4183*4882a593Smuzhiyun if (test_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags) ||
4184*4882a593Smuzhiyun test_bit(FD_VERIFY_BIT, &drive_state[drive].flags))
4185*4882a593Smuzhiyun return DISK_EVENT_MEDIA_CHANGE;
4186*4882a593Smuzhiyun
4187*4882a593Smuzhiyun if (time_after(jiffies, drive_state[drive].last_checked + drive_params[drive].checkfreq)) {
4188*4882a593Smuzhiyun if (lock_fdc(drive))
4189*4882a593Smuzhiyun return 0;
4190*4882a593Smuzhiyun poll_drive(false, 0);
4191*4882a593Smuzhiyun process_fd_request();
4192*4882a593Smuzhiyun }
4193*4882a593Smuzhiyun
4194*4882a593Smuzhiyun if (test_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags) ||
4195*4882a593Smuzhiyun test_bit(FD_VERIFY_BIT, &drive_state[drive].flags) ||
4196*4882a593Smuzhiyun test_bit(drive, &fake_change) ||
4197*4882a593Smuzhiyun drive_no_geom(drive))
4198*4882a593Smuzhiyun return DISK_EVENT_MEDIA_CHANGE;
4199*4882a593Smuzhiyun return 0;
4200*4882a593Smuzhiyun }
4201*4882a593Smuzhiyun
4202*4882a593Smuzhiyun /*
4203*4882a593Smuzhiyun * This implements "read block 0" for floppy_revalidate().
4204*4882a593Smuzhiyun * Needed for format autodetection, checking whether there is
4205*4882a593Smuzhiyun * a disk in the drive, and whether that disk is writable.
4206*4882a593Smuzhiyun */
4207*4882a593Smuzhiyun
4208*4882a593Smuzhiyun struct rb0_cbdata {
4209*4882a593Smuzhiyun int drive;
4210*4882a593Smuzhiyun struct completion complete;
4211*4882a593Smuzhiyun };
4212*4882a593Smuzhiyun
floppy_rb0_cb(struct bio * bio)4213*4882a593Smuzhiyun static void floppy_rb0_cb(struct bio *bio)
4214*4882a593Smuzhiyun {
4215*4882a593Smuzhiyun struct rb0_cbdata *cbdata = (struct rb0_cbdata *)bio->bi_private;
4216*4882a593Smuzhiyun int drive = cbdata->drive;
4217*4882a593Smuzhiyun
4218*4882a593Smuzhiyun if (bio->bi_status) {
4219*4882a593Smuzhiyun pr_info("floppy: error %d while reading block 0\n",
4220*4882a593Smuzhiyun bio->bi_status);
4221*4882a593Smuzhiyun set_bit(FD_OPEN_SHOULD_FAIL_BIT, &drive_state[drive].flags);
4222*4882a593Smuzhiyun }
4223*4882a593Smuzhiyun complete(&cbdata->complete);
4224*4882a593Smuzhiyun }
4225*4882a593Smuzhiyun
__floppy_read_block_0(struct block_device * bdev,int drive)4226*4882a593Smuzhiyun static int __floppy_read_block_0(struct block_device *bdev, int drive)
4227*4882a593Smuzhiyun {
4228*4882a593Smuzhiyun struct bio bio;
4229*4882a593Smuzhiyun struct bio_vec bio_vec;
4230*4882a593Smuzhiyun struct page *page;
4231*4882a593Smuzhiyun struct rb0_cbdata cbdata;
4232*4882a593Smuzhiyun
4233*4882a593Smuzhiyun page = alloc_page(GFP_NOIO);
4234*4882a593Smuzhiyun if (!page) {
4235*4882a593Smuzhiyun process_fd_request();
4236*4882a593Smuzhiyun return -ENOMEM;
4237*4882a593Smuzhiyun }
4238*4882a593Smuzhiyun
4239*4882a593Smuzhiyun cbdata.drive = drive;
4240*4882a593Smuzhiyun
4241*4882a593Smuzhiyun bio_init(&bio, &bio_vec, 1);
4242*4882a593Smuzhiyun bio_set_dev(&bio, bdev);
4243*4882a593Smuzhiyun bio_add_page(&bio, page, block_size(bdev), 0);
4244*4882a593Smuzhiyun
4245*4882a593Smuzhiyun bio.bi_iter.bi_sector = 0;
4246*4882a593Smuzhiyun bio.bi_flags |= (1 << BIO_QUIET);
4247*4882a593Smuzhiyun bio.bi_private = &cbdata;
4248*4882a593Smuzhiyun bio.bi_end_io = floppy_rb0_cb;
4249*4882a593Smuzhiyun bio_set_op_attrs(&bio, REQ_OP_READ, 0);
4250*4882a593Smuzhiyun
4251*4882a593Smuzhiyun init_completion(&cbdata.complete);
4252*4882a593Smuzhiyun
4253*4882a593Smuzhiyun submit_bio(&bio);
4254*4882a593Smuzhiyun process_fd_request();
4255*4882a593Smuzhiyun
4256*4882a593Smuzhiyun wait_for_completion(&cbdata.complete);
4257*4882a593Smuzhiyun
4258*4882a593Smuzhiyun __free_page(page);
4259*4882a593Smuzhiyun
4260*4882a593Smuzhiyun return 0;
4261*4882a593Smuzhiyun }
4262*4882a593Smuzhiyun
4263*4882a593Smuzhiyun /* revalidate the floppy disk, i.e. trigger format autodetection by reading
4264*4882a593Smuzhiyun * the bootblock (block 0). "Autodetection" is also needed to check whether
4265*4882a593Smuzhiyun * there is a disk in the drive at all... Thus we also do it for fixed
4266*4882a593Smuzhiyun * geometry formats */
floppy_revalidate(struct gendisk * disk)4267*4882a593Smuzhiyun static int floppy_revalidate(struct gendisk *disk)
4268*4882a593Smuzhiyun {
4269*4882a593Smuzhiyun int drive = (long)disk->private_data;
4270*4882a593Smuzhiyun int cf;
4271*4882a593Smuzhiyun int res = 0;
4272*4882a593Smuzhiyun
4273*4882a593Smuzhiyun if (test_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags) ||
4274*4882a593Smuzhiyun test_bit(FD_VERIFY_BIT, &drive_state[drive].flags) ||
4275*4882a593Smuzhiyun test_bit(drive, &fake_change) ||
4276*4882a593Smuzhiyun drive_no_geom(drive)) {
4277*4882a593Smuzhiyun if (WARN(atomic_read(&usage_count) == 0,
4278*4882a593Smuzhiyun "VFS: revalidate called on non-open device.\n"))
4279*4882a593Smuzhiyun return -EFAULT;
4280*4882a593Smuzhiyun
4281*4882a593Smuzhiyun res = lock_fdc(drive);
4282*4882a593Smuzhiyun if (res)
4283*4882a593Smuzhiyun return res;
4284*4882a593Smuzhiyun cf = (test_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags) ||
4285*4882a593Smuzhiyun test_bit(FD_VERIFY_BIT, &drive_state[drive].flags));
4286*4882a593Smuzhiyun if (!(cf || test_bit(drive, &fake_change) || drive_no_geom(drive))) {
4287*4882a593Smuzhiyun process_fd_request(); /*already done by another thread */
4288*4882a593Smuzhiyun return 0;
4289*4882a593Smuzhiyun }
4290*4882a593Smuzhiyun drive_state[drive].maxblock = 0;
4291*4882a593Smuzhiyun drive_state[drive].maxtrack = 0;
4292*4882a593Smuzhiyun if (buffer_drive == drive)
4293*4882a593Smuzhiyun buffer_track = -1;
4294*4882a593Smuzhiyun clear_bit(drive, &fake_change);
4295*4882a593Smuzhiyun clear_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags);
4296*4882a593Smuzhiyun if (cf)
4297*4882a593Smuzhiyun drive_state[drive].generation++;
4298*4882a593Smuzhiyun if (drive_no_geom(drive)) {
4299*4882a593Smuzhiyun /* auto-sensing */
4300*4882a593Smuzhiyun res = __floppy_read_block_0(opened_bdev[drive], drive);
4301*4882a593Smuzhiyun } else {
4302*4882a593Smuzhiyun if (cf)
4303*4882a593Smuzhiyun poll_drive(false, FD_RAW_NEED_DISK);
4304*4882a593Smuzhiyun process_fd_request();
4305*4882a593Smuzhiyun }
4306*4882a593Smuzhiyun }
4307*4882a593Smuzhiyun set_capacity(disk, floppy_sizes[drive_state[drive].fd_device]);
4308*4882a593Smuzhiyun return res;
4309*4882a593Smuzhiyun }
4310*4882a593Smuzhiyun
4311*4882a593Smuzhiyun static const struct block_device_operations floppy_fops = {
4312*4882a593Smuzhiyun .owner = THIS_MODULE,
4313*4882a593Smuzhiyun .open = floppy_open,
4314*4882a593Smuzhiyun .release = floppy_release,
4315*4882a593Smuzhiyun .ioctl = fd_ioctl,
4316*4882a593Smuzhiyun .getgeo = fd_getgeo,
4317*4882a593Smuzhiyun .check_events = floppy_check_events,
4318*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
4319*4882a593Smuzhiyun .compat_ioctl = fd_compat_ioctl,
4320*4882a593Smuzhiyun #endif
4321*4882a593Smuzhiyun };
4322*4882a593Smuzhiyun
4323*4882a593Smuzhiyun /*
4324*4882a593Smuzhiyun * Floppy Driver initialization
4325*4882a593Smuzhiyun * =============================
4326*4882a593Smuzhiyun */
4327*4882a593Smuzhiyun
4328*4882a593Smuzhiyun /* Determine the floppy disk controller type */
4329*4882a593Smuzhiyun /* This routine was written by David C. Niemi */
get_fdc_version(int fdc)4330*4882a593Smuzhiyun static char __init get_fdc_version(int fdc)
4331*4882a593Smuzhiyun {
4332*4882a593Smuzhiyun int r;
4333*4882a593Smuzhiyun
4334*4882a593Smuzhiyun output_byte(fdc, FD_DUMPREGS); /* 82072 and better know DUMPREGS */
4335*4882a593Smuzhiyun if (fdc_state[fdc].reset)
4336*4882a593Smuzhiyun return FDC_NONE;
4337*4882a593Smuzhiyun r = result(fdc);
4338*4882a593Smuzhiyun if (r <= 0x00)
4339*4882a593Smuzhiyun return FDC_NONE; /* No FDC present ??? */
4340*4882a593Smuzhiyun if ((r == 1) && (reply_buffer[0] == 0x80)) {
4341*4882a593Smuzhiyun pr_info("FDC %d is an 8272A\n", fdc);
4342*4882a593Smuzhiyun return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
4343*4882a593Smuzhiyun }
4344*4882a593Smuzhiyun if (r != 10) {
4345*4882a593Smuzhiyun pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
4346*4882a593Smuzhiyun fdc, r);
4347*4882a593Smuzhiyun return FDC_UNKNOWN;
4348*4882a593Smuzhiyun }
4349*4882a593Smuzhiyun
4350*4882a593Smuzhiyun if (!fdc_configure(fdc)) {
4351*4882a593Smuzhiyun pr_info("FDC %d is an 82072\n", fdc);
4352*4882a593Smuzhiyun return FDC_82072; /* 82072 doesn't know CONFIGURE */
4353*4882a593Smuzhiyun }
4354*4882a593Smuzhiyun
4355*4882a593Smuzhiyun output_byte(fdc, FD_PERPENDICULAR);
4356*4882a593Smuzhiyun if (need_more_output(fdc) == MORE_OUTPUT) {
4357*4882a593Smuzhiyun output_byte(fdc, 0);
4358*4882a593Smuzhiyun } else {
4359*4882a593Smuzhiyun pr_info("FDC %d is an 82072A\n", fdc);
4360*4882a593Smuzhiyun return FDC_82072A; /* 82072A as found on Sparcs. */
4361*4882a593Smuzhiyun }
4362*4882a593Smuzhiyun
4363*4882a593Smuzhiyun output_byte(fdc, FD_UNLOCK);
4364*4882a593Smuzhiyun r = result(fdc);
4365*4882a593Smuzhiyun if ((r == 1) && (reply_buffer[0] == 0x80)) {
4366*4882a593Smuzhiyun pr_info("FDC %d is a pre-1991 82077\n", fdc);
4367*4882a593Smuzhiyun return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
4368*4882a593Smuzhiyun * LOCK/UNLOCK */
4369*4882a593Smuzhiyun }
4370*4882a593Smuzhiyun if ((r != 1) || (reply_buffer[0] != 0x00)) {
4371*4882a593Smuzhiyun pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
4372*4882a593Smuzhiyun fdc, r);
4373*4882a593Smuzhiyun return FDC_UNKNOWN;
4374*4882a593Smuzhiyun }
4375*4882a593Smuzhiyun output_byte(fdc, FD_PARTID);
4376*4882a593Smuzhiyun r = result(fdc);
4377*4882a593Smuzhiyun if (r != 1) {
4378*4882a593Smuzhiyun pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
4379*4882a593Smuzhiyun fdc, r);
4380*4882a593Smuzhiyun return FDC_UNKNOWN;
4381*4882a593Smuzhiyun }
4382*4882a593Smuzhiyun if (reply_buffer[0] == 0x80) {
4383*4882a593Smuzhiyun pr_info("FDC %d is a post-1991 82077\n", fdc);
4384*4882a593Smuzhiyun return FDC_82077; /* Revised 82077AA passes all the tests */
4385*4882a593Smuzhiyun }
4386*4882a593Smuzhiyun switch (reply_buffer[0] >> 5) {
4387*4882a593Smuzhiyun case 0x0:
4388*4882a593Smuzhiyun /* Either a 82078-1 or a 82078SL running at 5Volt */
4389*4882a593Smuzhiyun pr_info("FDC %d is an 82078.\n", fdc);
4390*4882a593Smuzhiyun return FDC_82078;
4391*4882a593Smuzhiyun case 0x1:
4392*4882a593Smuzhiyun pr_info("FDC %d is a 44pin 82078\n", fdc);
4393*4882a593Smuzhiyun return FDC_82078;
4394*4882a593Smuzhiyun case 0x2:
4395*4882a593Smuzhiyun pr_info("FDC %d is a S82078B\n", fdc);
4396*4882a593Smuzhiyun return FDC_S82078B;
4397*4882a593Smuzhiyun case 0x3:
4398*4882a593Smuzhiyun pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
4399*4882a593Smuzhiyun return FDC_87306;
4400*4882a593Smuzhiyun default:
4401*4882a593Smuzhiyun pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
4402*4882a593Smuzhiyun fdc, reply_buffer[0] >> 5);
4403*4882a593Smuzhiyun return FDC_82078_UNKN;
4404*4882a593Smuzhiyun }
4405*4882a593Smuzhiyun } /* get_fdc_version */
4406*4882a593Smuzhiyun
4407*4882a593Smuzhiyun /* lilo configuration */
4408*4882a593Smuzhiyun
floppy_set_flags(int * ints,int param,int param2)4409*4882a593Smuzhiyun static void __init floppy_set_flags(int *ints, int param, int param2)
4410*4882a593Smuzhiyun {
4411*4882a593Smuzhiyun int i;
4412*4882a593Smuzhiyun
4413*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4414*4882a593Smuzhiyun if (param)
4415*4882a593Smuzhiyun default_drive_params[i].params.flags |= param2;
4416*4882a593Smuzhiyun else
4417*4882a593Smuzhiyun default_drive_params[i].params.flags &= ~param2;
4418*4882a593Smuzhiyun }
4419*4882a593Smuzhiyun DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param);
4420*4882a593Smuzhiyun }
4421*4882a593Smuzhiyun
daring(int * ints,int param,int param2)4422*4882a593Smuzhiyun static void __init daring(int *ints, int param, int param2)
4423*4882a593Smuzhiyun {
4424*4882a593Smuzhiyun int i;
4425*4882a593Smuzhiyun
4426*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(default_drive_params); i++) {
4427*4882a593Smuzhiyun if (param) {
4428*4882a593Smuzhiyun default_drive_params[i].params.select_delay = 0;
4429*4882a593Smuzhiyun default_drive_params[i].params.flags |=
4430*4882a593Smuzhiyun FD_SILENT_DCL_CLEAR;
4431*4882a593Smuzhiyun } else {
4432*4882a593Smuzhiyun default_drive_params[i].params.select_delay =
4433*4882a593Smuzhiyun 2 * HZ / 100;
4434*4882a593Smuzhiyun default_drive_params[i].params.flags &=
4435*4882a593Smuzhiyun ~FD_SILENT_DCL_CLEAR;
4436*4882a593Smuzhiyun }
4437*4882a593Smuzhiyun }
4438*4882a593Smuzhiyun DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken");
4439*4882a593Smuzhiyun }
4440*4882a593Smuzhiyun
set_cmos(int * ints,int dummy,int dummy2)4441*4882a593Smuzhiyun static void __init set_cmos(int *ints, int dummy, int dummy2)
4442*4882a593Smuzhiyun {
4443*4882a593Smuzhiyun int current_drive = 0;
4444*4882a593Smuzhiyun
4445*4882a593Smuzhiyun if (ints[0] != 2) {
4446*4882a593Smuzhiyun DPRINT("wrong number of parameters for CMOS\n");
4447*4882a593Smuzhiyun return;
4448*4882a593Smuzhiyun }
4449*4882a593Smuzhiyun current_drive = ints[1];
4450*4882a593Smuzhiyun if (current_drive < 0 || current_drive >= 8) {
4451*4882a593Smuzhiyun DPRINT("bad drive for set_cmos\n");
4452*4882a593Smuzhiyun return;
4453*4882a593Smuzhiyun }
4454*4882a593Smuzhiyun #if N_FDC > 1
4455*4882a593Smuzhiyun if (current_drive >= 4 && !FDC2)
4456*4882a593Smuzhiyun FDC2 = 0x370;
4457*4882a593Smuzhiyun #endif
4458*4882a593Smuzhiyun drive_params[current_drive].cmos = ints[2];
4459*4882a593Smuzhiyun DPRINT("setting CMOS code to %d\n", ints[2]);
4460*4882a593Smuzhiyun }
4461*4882a593Smuzhiyun
4462*4882a593Smuzhiyun static struct param_table {
4463*4882a593Smuzhiyun const char *name;
4464*4882a593Smuzhiyun void (*fn) (int *ints, int param, int param2);
4465*4882a593Smuzhiyun int *var;
4466*4882a593Smuzhiyun int def_param;
4467*4882a593Smuzhiyun int param2;
4468*4882a593Smuzhiyun } config_params[] __initdata = {
4469*4882a593Smuzhiyun {"allowed_drive_mask", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4470*4882a593Smuzhiyun {"all_drives", NULL, &allowed_drive_mask, 0xff, 0}, /* obsolete */
4471*4882a593Smuzhiyun {"asus_pci", NULL, &allowed_drive_mask, 0x33, 0},
4472*4882a593Smuzhiyun {"irq", NULL, &FLOPPY_IRQ, 6, 0},
4473*4882a593Smuzhiyun {"dma", NULL, &FLOPPY_DMA, 2, 0},
4474*4882a593Smuzhiyun {"daring", daring, NULL, 1, 0},
4475*4882a593Smuzhiyun #if N_FDC > 1
4476*4882a593Smuzhiyun {"two_fdc", NULL, &FDC2, 0x370, 0},
4477*4882a593Smuzhiyun {"one_fdc", NULL, &FDC2, 0, 0},
4478*4882a593Smuzhiyun #endif
4479*4882a593Smuzhiyun {"thinkpad", floppy_set_flags, NULL, 1, FD_INVERTED_DCL},
4480*4882a593Smuzhiyun {"broken_dcl", floppy_set_flags, NULL, 1, FD_BROKEN_DCL},
4481*4882a593Smuzhiyun {"messages", floppy_set_flags, NULL, 1, FTD_MSG},
4482*4882a593Smuzhiyun {"silent_dcl_clear", floppy_set_flags, NULL, 1, FD_SILENT_DCL_CLEAR},
4483*4882a593Smuzhiyun {"debug", floppy_set_flags, NULL, 1, FD_DEBUG},
4484*4882a593Smuzhiyun {"nodma", NULL, &can_use_virtual_dma, 1, 0},
4485*4882a593Smuzhiyun {"omnibook", NULL, &can_use_virtual_dma, 1, 0},
4486*4882a593Smuzhiyun {"yesdma", NULL, &can_use_virtual_dma, 0, 0},
4487*4882a593Smuzhiyun {"fifo_depth", NULL, &fifo_depth, 0xa, 0},
4488*4882a593Smuzhiyun {"nofifo", NULL, &no_fifo, 0x20, 0},
4489*4882a593Smuzhiyun {"usefifo", NULL, &no_fifo, 0, 0},
4490*4882a593Smuzhiyun {"cmos", set_cmos, NULL, 0, 0},
4491*4882a593Smuzhiyun {"slow", NULL, &slow_floppy, 1, 0},
4492*4882a593Smuzhiyun {"unexpected_interrupts", NULL, &print_unex, 1, 0},
4493*4882a593Smuzhiyun {"no_unexpected_interrupts", NULL, &print_unex, 0, 0},
4494*4882a593Smuzhiyun {"L40SX", NULL, &print_unex, 0, 0}
4495*4882a593Smuzhiyun
4496*4882a593Smuzhiyun EXTRA_FLOPPY_PARAMS
4497*4882a593Smuzhiyun };
4498*4882a593Smuzhiyun
floppy_setup(char * str)4499*4882a593Smuzhiyun static int __init floppy_setup(char *str)
4500*4882a593Smuzhiyun {
4501*4882a593Smuzhiyun int i;
4502*4882a593Smuzhiyun int param;
4503*4882a593Smuzhiyun int ints[11];
4504*4882a593Smuzhiyun
4505*4882a593Smuzhiyun str = get_options(str, ARRAY_SIZE(ints), ints);
4506*4882a593Smuzhiyun if (str) {
4507*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(config_params); i++) {
4508*4882a593Smuzhiyun if (strcmp(str, config_params[i].name) == 0) {
4509*4882a593Smuzhiyun if (ints[0])
4510*4882a593Smuzhiyun param = ints[1];
4511*4882a593Smuzhiyun else
4512*4882a593Smuzhiyun param = config_params[i].def_param;
4513*4882a593Smuzhiyun if (config_params[i].fn)
4514*4882a593Smuzhiyun config_params[i].fn(ints, param,
4515*4882a593Smuzhiyun config_params[i].
4516*4882a593Smuzhiyun param2);
4517*4882a593Smuzhiyun if (config_params[i].var) {
4518*4882a593Smuzhiyun DPRINT("%s=%d\n", str, param);
4519*4882a593Smuzhiyun *config_params[i].var = param;
4520*4882a593Smuzhiyun }
4521*4882a593Smuzhiyun return 1;
4522*4882a593Smuzhiyun }
4523*4882a593Smuzhiyun }
4524*4882a593Smuzhiyun }
4525*4882a593Smuzhiyun if (str) {
4526*4882a593Smuzhiyun DPRINT("unknown floppy option [%s]\n", str);
4527*4882a593Smuzhiyun
4528*4882a593Smuzhiyun DPRINT("allowed options are:");
4529*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(config_params); i++)
4530*4882a593Smuzhiyun pr_cont(" %s", config_params[i].name);
4531*4882a593Smuzhiyun pr_cont("\n");
4532*4882a593Smuzhiyun } else
4533*4882a593Smuzhiyun DPRINT("botched floppy option\n");
4534*4882a593Smuzhiyun DPRINT("Read Documentation/admin-guide/blockdev/floppy.rst\n");
4535*4882a593Smuzhiyun return 0;
4536*4882a593Smuzhiyun }
4537*4882a593Smuzhiyun
4538*4882a593Smuzhiyun static int have_no_fdc = -ENODEV;
4539*4882a593Smuzhiyun
floppy_cmos_show(struct device * dev,struct device_attribute * attr,char * buf)4540*4882a593Smuzhiyun static ssize_t floppy_cmos_show(struct device *dev,
4541*4882a593Smuzhiyun struct device_attribute *attr, char *buf)
4542*4882a593Smuzhiyun {
4543*4882a593Smuzhiyun struct platform_device *p = to_platform_device(dev);
4544*4882a593Smuzhiyun int drive;
4545*4882a593Smuzhiyun
4546*4882a593Smuzhiyun drive = p->id;
4547*4882a593Smuzhiyun return sprintf(buf, "%X\n", drive_params[drive].cmos);
4548*4882a593Smuzhiyun }
4549*4882a593Smuzhiyun
4550*4882a593Smuzhiyun static DEVICE_ATTR(cmos, 0444, floppy_cmos_show, NULL);
4551*4882a593Smuzhiyun
4552*4882a593Smuzhiyun static struct attribute *floppy_dev_attrs[] = {
4553*4882a593Smuzhiyun &dev_attr_cmos.attr,
4554*4882a593Smuzhiyun NULL
4555*4882a593Smuzhiyun };
4556*4882a593Smuzhiyun
4557*4882a593Smuzhiyun ATTRIBUTE_GROUPS(floppy_dev);
4558*4882a593Smuzhiyun
floppy_device_release(struct device * dev)4559*4882a593Smuzhiyun static void floppy_device_release(struct device *dev)
4560*4882a593Smuzhiyun {
4561*4882a593Smuzhiyun }
4562*4882a593Smuzhiyun
floppy_resume(struct device * dev)4563*4882a593Smuzhiyun static int floppy_resume(struct device *dev)
4564*4882a593Smuzhiyun {
4565*4882a593Smuzhiyun int fdc;
4566*4882a593Smuzhiyun int saved_drive;
4567*4882a593Smuzhiyun
4568*4882a593Smuzhiyun saved_drive = current_drive;
4569*4882a593Smuzhiyun for (fdc = 0; fdc < N_FDC; fdc++)
4570*4882a593Smuzhiyun if (fdc_state[fdc].address != -1)
4571*4882a593Smuzhiyun user_reset_fdc(REVDRIVE(fdc, 0), FD_RESET_ALWAYS, false);
4572*4882a593Smuzhiyun set_fdc(saved_drive);
4573*4882a593Smuzhiyun return 0;
4574*4882a593Smuzhiyun }
4575*4882a593Smuzhiyun
4576*4882a593Smuzhiyun static const struct dev_pm_ops floppy_pm_ops = {
4577*4882a593Smuzhiyun .resume = floppy_resume,
4578*4882a593Smuzhiyun .restore = floppy_resume,
4579*4882a593Smuzhiyun };
4580*4882a593Smuzhiyun
4581*4882a593Smuzhiyun static struct platform_driver floppy_driver = {
4582*4882a593Smuzhiyun .driver = {
4583*4882a593Smuzhiyun .name = "floppy",
4584*4882a593Smuzhiyun .pm = &floppy_pm_ops,
4585*4882a593Smuzhiyun },
4586*4882a593Smuzhiyun };
4587*4882a593Smuzhiyun
4588*4882a593Smuzhiyun static const struct blk_mq_ops floppy_mq_ops = {
4589*4882a593Smuzhiyun .queue_rq = floppy_queue_rq,
4590*4882a593Smuzhiyun };
4591*4882a593Smuzhiyun
4592*4882a593Smuzhiyun static struct platform_device floppy_device[N_DRIVE];
4593*4882a593Smuzhiyun
floppy_available(int drive)4594*4882a593Smuzhiyun static bool floppy_available(int drive)
4595*4882a593Smuzhiyun {
4596*4882a593Smuzhiyun if (!(allowed_drive_mask & (1 << drive)))
4597*4882a593Smuzhiyun return false;
4598*4882a593Smuzhiyun if (fdc_state[FDC(drive)].version == FDC_NONE)
4599*4882a593Smuzhiyun return false;
4600*4882a593Smuzhiyun return true;
4601*4882a593Smuzhiyun }
4602*4882a593Smuzhiyun
floppy_find(dev_t dev,int * part,void * data)4603*4882a593Smuzhiyun static struct kobject *floppy_find(dev_t dev, int *part, void *data)
4604*4882a593Smuzhiyun {
4605*4882a593Smuzhiyun int drive = (*part & 3) | ((*part & 0x80) >> 5);
4606*4882a593Smuzhiyun if (drive >= N_DRIVE || !floppy_available(drive))
4607*4882a593Smuzhiyun return NULL;
4608*4882a593Smuzhiyun if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
4609*4882a593Smuzhiyun return NULL;
4610*4882a593Smuzhiyun *part = 0;
4611*4882a593Smuzhiyun return get_disk_and_module(disks[drive]);
4612*4882a593Smuzhiyun }
4613*4882a593Smuzhiyun
do_floppy_init(void)4614*4882a593Smuzhiyun static int __init do_floppy_init(void)
4615*4882a593Smuzhiyun {
4616*4882a593Smuzhiyun int i, unit, drive, err;
4617*4882a593Smuzhiyun
4618*4882a593Smuzhiyun set_debugt();
4619*4882a593Smuzhiyun interruptjiffies = resultjiffies = jiffies;
4620*4882a593Smuzhiyun
4621*4882a593Smuzhiyun #if defined(CONFIG_PPC)
4622*4882a593Smuzhiyun if (check_legacy_ioport(FDC1))
4623*4882a593Smuzhiyun return -ENODEV;
4624*4882a593Smuzhiyun #endif
4625*4882a593Smuzhiyun
4626*4882a593Smuzhiyun raw_cmd = NULL;
4627*4882a593Smuzhiyun
4628*4882a593Smuzhiyun floppy_wq = alloc_ordered_workqueue("floppy", 0);
4629*4882a593Smuzhiyun if (!floppy_wq)
4630*4882a593Smuzhiyun return -ENOMEM;
4631*4882a593Smuzhiyun
4632*4882a593Smuzhiyun for (drive = 0; drive < N_DRIVE; drive++) {
4633*4882a593Smuzhiyun disks[drive] = alloc_disk(1);
4634*4882a593Smuzhiyun if (!disks[drive]) {
4635*4882a593Smuzhiyun err = -ENOMEM;
4636*4882a593Smuzhiyun goto out_put_disk;
4637*4882a593Smuzhiyun }
4638*4882a593Smuzhiyun
4639*4882a593Smuzhiyun disks[drive]->queue = blk_mq_init_sq_queue(&tag_sets[drive],
4640*4882a593Smuzhiyun &floppy_mq_ops, 2,
4641*4882a593Smuzhiyun BLK_MQ_F_SHOULD_MERGE);
4642*4882a593Smuzhiyun if (IS_ERR(disks[drive]->queue)) {
4643*4882a593Smuzhiyun err = PTR_ERR(disks[drive]->queue);
4644*4882a593Smuzhiyun disks[drive]->queue = NULL;
4645*4882a593Smuzhiyun goto out_put_disk;
4646*4882a593Smuzhiyun }
4647*4882a593Smuzhiyun
4648*4882a593Smuzhiyun blk_queue_bounce_limit(disks[drive]->queue, BLK_BOUNCE_HIGH);
4649*4882a593Smuzhiyun blk_queue_max_hw_sectors(disks[drive]->queue, 64);
4650*4882a593Smuzhiyun disks[drive]->major = FLOPPY_MAJOR;
4651*4882a593Smuzhiyun disks[drive]->first_minor = TOMINOR(drive);
4652*4882a593Smuzhiyun disks[drive]->fops = &floppy_fops;
4653*4882a593Smuzhiyun disks[drive]->events = DISK_EVENT_MEDIA_CHANGE;
4654*4882a593Smuzhiyun sprintf(disks[drive]->disk_name, "fd%d", drive);
4655*4882a593Smuzhiyun
4656*4882a593Smuzhiyun timer_setup(&motor_off_timer[drive], motor_off_callback, 0);
4657*4882a593Smuzhiyun }
4658*4882a593Smuzhiyun
4659*4882a593Smuzhiyun err = register_blkdev(FLOPPY_MAJOR, "fd");
4660*4882a593Smuzhiyun if (err)
4661*4882a593Smuzhiyun goto out_put_disk;
4662*4882a593Smuzhiyun
4663*4882a593Smuzhiyun err = platform_driver_register(&floppy_driver);
4664*4882a593Smuzhiyun if (err)
4665*4882a593Smuzhiyun goto out_unreg_blkdev;
4666*4882a593Smuzhiyun
4667*4882a593Smuzhiyun blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
4668*4882a593Smuzhiyun floppy_find, NULL, NULL);
4669*4882a593Smuzhiyun
4670*4882a593Smuzhiyun for (i = 0; i < 256; i++)
4671*4882a593Smuzhiyun if (ITYPE(i))
4672*4882a593Smuzhiyun floppy_sizes[i] = floppy_type[ITYPE(i)].size;
4673*4882a593Smuzhiyun else
4674*4882a593Smuzhiyun floppy_sizes[i] = MAX_DISK_SIZE << 1;
4675*4882a593Smuzhiyun
4676*4882a593Smuzhiyun reschedule_timeout(MAXTIMEOUT, "floppy init");
4677*4882a593Smuzhiyun config_types();
4678*4882a593Smuzhiyun
4679*4882a593Smuzhiyun for (i = 0; i < N_FDC; i++) {
4680*4882a593Smuzhiyun memset(&fdc_state[i], 0, sizeof(*fdc_state));
4681*4882a593Smuzhiyun fdc_state[i].dtr = -1;
4682*4882a593Smuzhiyun fdc_state[i].dor = 0x4;
4683*4882a593Smuzhiyun #if defined(__sparc__) || defined(__mc68000__)
4684*4882a593Smuzhiyun /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
4685*4882a593Smuzhiyun #ifdef __mc68000__
4686*4882a593Smuzhiyun if (MACH_IS_SUN3X)
4687*4882a593Smuzhiyun #endif
4688*4882a593Smuzhiyun fdc_state[i].version = FDC_82072A;
4689*4882a593Smuzhiyun #endif
4690*4882a593Smuzhiyun }
4691*4882a593Smuzhiyun
4692*4882a593Smuzhiyun use_virtual_dma = can_use_virtual_dma & 1;
4693*4882a593Smuzhiyun fdc_state[0].address = FDC1;
4694*4882a593Smuzhiyun if (fdc_state[0].address == -1) {
4695*4882a593Smuzhiyun cancel_delayed_work(&fd_timeout);
4696*4882a593Smuzhiyun err = -ENODEV;
4697*4882a593Smuzhiyun goto out_unreg_region;
4698*4882a593Smuzhiyun }
4699*4882a593Smuzhiyun #if N_FDC > 1
4700*4882a593Smuzhiyun fdc_state[1].address = FDC2;
4701*4882a593Smuzhiyun #endif
4702*4882a593Smuzhiyun
4703*4882a593Smuzhiyun current_fdc = 0; /* reset fdc in case of unexpected interrupt */
4704*4882a593Smuzhiyun err = floppy_grab_irq_and_dma();
4705*4882a593Smuzhiyun if (err) {
4706*4882a593Smuzhiyun cancel_delayed_work(&fd_timeout);
4707*4882a593Smuzhiyun err = -EBUSY;
4708*4882a593Smuzhiyun goto out_unreg_region;
4709*4882a593Smuzhiyun }
4710*4882a593Smuzhiyun
4711*4882a593Smuzhiyun /* initialise drive state */
4712*4882a593Smuzhiyun for (drive = 0; drive < N_DRIVE; drive++) {
4713*4882a593Smuzhiyun memset(&drive_state[drive], 0, sizeof(drive_state[drive]));
4714*4882a593Smuzhiyun memset(&write_errors[drive], 0, sizeof(write_errors[drive]));
4715*4882a593Smuzhiyun set_bit(FD_DISK_NEWCHANGE_BIT, &drive_state[drive].flags);
4716*4882a593Smuzhiyun set_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags);
4717*4882a593Smuzhiyun set_bit(FD_VERIFY_BIT, &drive_state[drive].flags);
4718*4882a593Smuzhiyun drive_state[drive].fd_device = -1;
4719*4882a593Smuzhiyun floppy_track_buffer = NULL;
4720*4882a593Smuzhiyun max_buffer_sectors = 0;
4721*4882a593Smuzhiyun }
4722*4882a593Smuzhiyun /*
4723*4882a593Smuzhiyun * Small 10 msec delay to let through any interrupt that
4724*4882a593Smuzhiyun * initialization might have triggered, to not
4725*4882a593Smuzhiyun * confuse detection:
4726*4882a593Smuzhiyun */
4727*4882a593Smuzhiyun msleep(10);
4728*4882a593Smuzhiyun
4729*4882a593Smuzhiyun for (i = 0; i < N_FDC; i++) {
4730*4882a593Smuzhiyun fdc_state[i].driver_version = FD_DRIVER_VERSION;
4731*4882a593Smuzhiyun for (unit = 0; unit < 4; unit++)
4732*4882a593Smuzhiyun fdc_state[i].track[unit] = 0;
4733*4882a593Smuzhiyun if (fdc_state[i].address == -1)
4734*4882a593Smuzhiyun continue;
4735*4882a593Smuzhiyun fdc_state[i].rawcmd = 2;
4736*4882a593Smuzhiyun if (user_reset_fdc(REVDRIVE(i, 0), FD_RESET_ALWAYS, false)) {
4737*4882a593Smuzhiyun /* free ioports reserved by floppy_grab_irq_and_dma() */
4738*4882a593Smuzhiyun floppy_release_regions(i);
4739*4882a593Smuzhiyun fdc_state[i].address = -1;
4740*4882a593Smuzhiyun fdc_state[i].version = FDC_NONE;
4741*4882a593Smuzhiyun continue;
4742*4882a593Smuzhiyun }
4743*4882a593Smuzhiyun /* Try to determine the floppy controller type */
4744*4882a593Smuzhiyun fdc_state[i].version = get_fdc_version(i);
4745*4882a593Smuzhiyun if (fdc_state[i].version == FDC_NONE) {
4746*4882a593Smuzhiyun /* free ioports reserved by floppy_grab_irq_and_dma() */
4747*4882a593Smuzhiyun floppy_release_regions(i);
4748*4882a593Smuzhiyun fdc_state[i].address = -1;
4749*4882a593Smuzhiyun continue;
4750*4882a593Smuzhiyun }
4751*4882a593Smuzhiyun if (can_use_virtual_dma == 2 &&
4752*4882a593Smuzhiyun fdc_state[i].version < FDC_82072A)
4753*4882a593Smuzhiyun can_use_virtual_dma = 0;
4754*4882a593Smuzhiyun
4755*4882a593Smuzhiyun have_no_fdc = 0;
4756*4882a593Smuzhiyun /* Not all FDCs seem to be able to handle the version command
4757*4882a593Smuzhiyun * properly, so force a reset for the standard FDC clones,
4758*4882a593Smuzhiyun * to avoid interrupt garbage.
4759*4882a593Smuzhiyun */
4760*4882a593Smuzhiyun user_reset_fdc(REVDRIVE(i, 0), FD_RESET_ALWAYS, false);
4761*4882a593Smuzhiyun }
4762*4882a593Smuzhiyun current_fdc = 0;
4763*4882a593Smuzhiyun cancel_delayed_work(&fd_timeout);
4764*4882a593Smuzhiyun current_drive = 0;
4765*4882a593Smuzhiyun initialized = true;
4766*4882a593Smuzhiyun if (have_no_fdc) {
4767*4882a593Smuzhiyun DPRINT("no floppy controllers found\n");
4768*4882a593Smuzhiyun err = have_no_fdc;
4769*4882a593Smuzhiyun goto out_release_dma;
4770*4882a593Smuzhiyun }
4771*4882a593Smuzhiyun
4772*4882a593Smuzhiyun for (drive = 0; drive < N_DRIVE; drive++) {
4773*4882a593Smuzhiyun if (!floppy_available(drive))
4774*4882a593Smuzhiyun continue;
4775*4882a593Smuzhiyun
4776*4882a593Smuzhiyun floppy_device[drive].name = floppy_device_name;
4777*4882a593Smuzhiyun floppy_device[drive].id = drive;
4778*4882a593Smuzhiyun floppy_device[drive].dev.release = floppy_device_release;
4779*4882a593Smuzhiyun floppy_device[drive].dev.groups = floppy_dev_groups;
4780*4882a593Smuzhiyun
4781*4882a593Smuzhiyun err = platform_device_register(&floppy_device[drive]);
4782*4882a593Smuzhiyun if (err)
4783*4882a593Smuzhiyun goto out_remove_drives;
4784*4882a593Smuzhiyun
4785*4882a593Smuzhiyun /* to be cleaned up... */
4786*4882a593Smuzhiyun disks[drive]->private_data = (void *)(long)drive;
4787*4882a593Smuzhiyun disks[drive]->flags |= GENHD_FL_REMOVABLE;
4788*4882a593Smuzhiyun device_add_disk(&floppy_device[drive].dev, disks[drive], NULL);
4789*4882a593Smuzhiyun }
4790*4882a593Smuzhiyun
4791*4882a593Smuzhiyun return 0;
4792*4882a593Smuzhiyun
4793*4882a593Smuzhiyun out_remove_drives:
4794*4882a593Smuzhiyun while (drive--) {
4795*4882a593Smuzhiyun if (floppy_available(drive)) {
4796*4882a593Smuzhiyun del_gendisk(disks[drive]);
4797*4882a593Smuzhiyun platform_device_unregister(&floppy_device[drive]);
4798*4882a593Smuzhiyun }
4799*4882a593Smuzhiyun }
4800*4882a593Smuzhiyun out_release_dma:
4801*4882a593Smuzhiyun if (atomic_read(&usage_count))
4802*4882a593Smuzhiyun floppy_release_irq_and_dma();
4803*4882a593Smuzhiyun out_unreg_region:
4804*4882a593Smuzhiyun blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
4805*4882a593Smuzhiyun platform_driver_unregister(&floppy_driver);
4806*4882a593Smuzhiyun out_unreg_blkdev:
4807*4882a593Smuzhiyun unregister_blkdev(FLOPPY_MAJOR, "fd");
4808*4882a593Smuzhiyun out_put_disk:
4809*4882a593Smuzhiyun destroy_workqueue(floppy_wq);
4810*4882a593Smuzhiyun for (drive = 0; drive < N_DRIVE; drive++) {
4811*4882a593Smuzhiyun if (!disks[drive])
4812*4882a593Smuzhiyun break;
4813*4882a593Smuzhiyun if (disks[drive]->queue) {
4814*4882a593Smuzhiyun del_timer_sync(&motor_off_timer[drive]);
4815*4882a593Smuzhiyun blk_cleanup_queue(disks[drive]->queue);
4816*4882a593Smuzhiyun disks[drive]->queue = NULL;
4817*4882a593Smuzhiyun blk_mq_free_tag_set(&tag_sets[drive]);
4818*4882a593Smuzhiyun }
4819*4882a593Smuzhiyun put_disk(disks[drive]);
4820*4882a593Smuzhiyun }
4821*4882a593Smuzhiyun return err;
4822*4882a593Smuzhiyun }
4823*4882a593Smuzhiyun
4824*4882a593Smuzhiyun #ifndef MODULE
floppy_async_init(void * data,async_cookie_t cookie)4825*4882a593Smuzhiyun static __init void floppy_async_init(void *data, async_cookie_t cookie)
4826*4882a593Smuzhiyun {
4827*4882a593Smuzhiyun do_floppy_init();
4828*4882a593Smuzhiyun }
4829*4882a593Smuzhiyun #endif
4830*4882a593Smuzhiyun
floppy_init(void)4831*4882a593Smuzhiyun static int __init floppy_init(void)
4832*4882a593Smuzhiyun {
4833*4882a593Smuzhiyun #ifdef MODULE
4834*4882a593Smuzhiyun return do_floppy_init();
4835*4882a593Smuzhiyun #else
4836*4882a593Smuzhiyun /* Don't hold up the bootup by the floppy initialization */
4837*4882a593Smuzhiyun async_schedule(floppy_async_init, NULL);
4838*4882a593Smuzhiyun return 0;
4839*4882a593Smuzhiyun #endif
4840*4882a593Smuzhiyun }
4841*4882a593Smuzhiyun
4842*4882a593Smuzhiyun static const struct io_region {
4843*4882a593Smuzhiyun int offset;
4844*4882a593Smuzhiyun int size;
4845*4882a593Smuzhiyun } io_regions[] = {
4846*4882a593Smuzhiyun { 2, 1 },
4847*4882a593Smuzhiyun /* address + 3 is sometimes reserved by pnp bios for motherboard */
4848*4882a593Smuzhiyun { 4, 2 },
4849*4882a593Smuzhiyun /* address + 6 is reserved, and may be taken by IDE.
4850*4882a593Smuzhiyun * Unfortunately, Adaptec doesn't know this :-(, */
4851*4882a593Smuzhiyun { 7, 1 },
4852*4882a593Smuzhiyun };
4853*4882a593Smuzhiyun
floppy_release_allocated_regions(int fdc,const struct io_region * p)4854*4882a593Smuzhiyun static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
4855*4882a593Smuzhiyun {
4856*4882a593Smuzhiyun while (p != io_regions) {
4857*4882a593Smuzhiyun p--;
4858*4882a593Smuzhiyun release_region(fdc_state[fdc].address + p->offset, p->size);
4859*4882a593Smuzhiyun }
4860*4882a593Smuzhiyun }
4861*4882a593Smuzhiyun
4862*4882a593Smuzhiyun #define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
4863*4882a593Smuzhiyun
floppy_request_regions(int fdc)4864*4882a593Smuzhiyun static int floppy_request_regions(int fdc)
4865*4882a593Smuzhiyun {
4866*4882a593Smuzhiyun const struct io_region *p;
4867*4882a593Smuzhiyun
4868*4882a593Smuzhiyun for (p = io_regions; p < ARRAY_END(io_regions); p++) {
4869*4882a593Smuzhiyun if (!request_region(fdc_state[fdc].address + p->offset,
4870*4882a593Smuzhiyun p->size, "floppy")) {
4871*4882a593Smuzhiyun DPRINT("Floppy io-port 0x%04lx in use\n",
4872*4882a593Smuzhiyun fdc_state[fdc].address + p->offset);
4873*4882a593Smuzhiyun floppy_release_allocated_regions(fdc, p);
4874*4882a593Smuzhiyun return -EBUSY;
4875*4882a593Smuzhiyun }
4876*4882a593Smuzhiyun }
4877*4882a593Smuzhiyun return 0;
4878*4882a593Smuzhiyun }
4879*4882a593Smuzhiyun
floppy_release_regions(int fdc)4880*4882a593Smuzhiyun static void floppy_release_regions(int fdc)
4881*4882a593Smuzhiyun {
4882*4882a593Smuzhiyun floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
4883*4882a593Smuzhiyun }
4884*4882a593Smuzhiyun
floppy_grab_irq_and_dma(void)4885*4882a593Smuzhiyun static int floppy_grab_irq_and_dma(void)
4886*4882a593Smuzhiyun {
4887*4882a593Smuzhiyun int fdc;
4888*4882a593Smuzhiyun
4889*4882a593Smuzhiyun if (atomic_inc_return(&usage_count) > 1)
4890*4882a593Smuzhiyun return 0;
4891*4882a593Smuzhiyun
4892*4882a593Smuzhiyun /*
4893*4882a593Smuzhiyun * We might have scheduled a free_irq(), wait it to
4894*4882a593Smuzhiyun * drain first:
4895*4882a593Smuzhiyun */
4896*4882a593Smuzhiyun flush_workqueue(floppy_wq);
4897*4882a593Smuzhiyun
4898*4882a593Smuzhiyun if (fd_request_irq()) {
4899*4882a593Smuzhiyun DPRINT("Unable to grab IRQ%d for the floppy driver\n",
4900*4882a593Smuzhiyun FLOPPY_IRQ);
4901*4882a593Smuzhiyun atomic_dec(&usage_count);
4902*4882a593Smuzhiyun return -1;
4903*4882a593Smuzhiyun }
4904*4882a593Smuzhiyun if (fd_request_dma()) {
4905*4882a593Smuzhiyun DPRINT("Unable to grab DMA%d for the floppy driver\n",
4906*4882a593Smuzhiyun FLOPPY_DMA);
4907*4882a593Smuzhiyun if (can_use_virtual_dma & 2)
4908*4882a593Smuzhiyun use_virtual_dma = can_use_virtual_dma = 1;
4909*4882a593Smuzhiyun if (!(can_use_virtual_dma & 1)) {
4910*4882a593Smuzhiyun fd_free_irq();
4911*4882a593Smuzhiyun atomic_dec(&usage_count);
4912*4882a593Smuzhiyun return -1;
4913*4882a593Smuzhiyun }
4914*4882a593Smuzhiyun }
4915*4882a593Smuzhiyun
4916*4882a593Smuzhiyun for (fdc = 0; fdc < N_FDC; fdc++) {
4917*4882a593Smuzhiyun if (fdc_state[fdc].address != -1) {
4918*4882a593Smuzhiyun if (floppy_request_regions(fdc))
4919*4882a593Smuzhiyun goto cleanup;
4920*4882a593Smuzhiyun }
4921*4882a593Smuzhiyun }
4922*4882a593Smuzhiyun for (fdc = 0; fdc < N_FDC; fdc++) {
4923*4882a593Smuzhiyun if (fdc_state[fdc].address != -1) {
4924*4882a593Smuzhiyun reset_fdc_info(fdc, 1);
4925*4882a593Smuzhiyun fdc_outb(fdc_state[fdc].dor, fdc, FD_DOR);
4926*4882a593Smuzhiyun }
4927*4882a593Smuzhiyun }
4928*4882a593Smuzhiyun
4929*4882a593Smuzhiyun set_dor(0, ~0, 8); /* avoid immediate interrupt */
4930*4882a593Smuzhiyun
4931*4882a593Smuzhiyun for (fdc = 0; fdc < N_FDC; fdc++)
4932*4882a593Smuzhiyun if (fdc_state[fdc].address != -1)
4933*4882a593Smuzhiyun fdc_outb(fdc_state[fdc].dor, fdc, FD_DOR);
4934*4882a593Smuzhiyun /*
4935*4882a593Smuzhiyun * The driver will try and free resources and relies on us
4936*4882a593Smuzhiyun * to know if they were allocated or not.
4937*4882a593Smuzhiyun */
4938*4882a593Smuzhiyun current_fdc = 0;
4939*4882a593Smuzhiyun irqdma_allocated = 1;
4940*4882a593Smuzhiyun return 0;
4941*4882a593Smuzhiyun cleanup:
4942*4882a593Smuzhiyun fd_free_irq();
4943*4882a593Smuzhiyun fd_free_dma();
4944*4882a593Smuzhiyun while (--fdc >= 0)
4945*4882a593Smuzhiyun floppy_release_regions(fdc);
4946*4882a593Smuzhiyun current_fdc = 0;
4947*4882a593Smuzhiyun atomic_dec(&usage_count);
4948*4882a593Smuzhiyun return -1;
4949*4882a593Smuzhiyun }
4950*4882a593Smuzhiyun
floppy_release_irq_and_dma(void)4951*4882a593Smuzhiyun static void floppy_release_irq_and_dma(void)
4952*4882a593Smuzhiyun {
4953*4882a593Smuzhiyun int fdc;
4954*4882a593Smuzhiyun #ifndef __sparc__
4955*4882a593Smuzhiyun int drive;
4956*4882a593Smuzhiyun #endif
4957*4882a593Smuzhiyun long tmpsize;
4958*4882a593Smuzhiyun unsigned long tmpaddr;
4959*4882a593Smuzhiyun
4960*4882a593Smuzhiyun if (!atomic_dec_and_test(&usage_count))
4961*4882a593Smuzhiyun return;
4962*4882a593Smuzhiyun
4963*4882a593Smuzhiyun if (irqdma_allocated) {
4964*4882a593Smuzhiyun fd_disable_dma();
4965*4882a593Smuzhiyun fd_free_dma();
4966*4882a593Smuzhiyun fd_free_irq();
4967*4882a593Smuzhiyun irqdma_allocated = 0;
4968*4882a593Smuzhiyun }
4969*4882a593Smuzhiyun set_dor(0, ~0, 8);
4970*4882a593Smuzhiyun #if N_FDC > 1
4971*4882a593Smuzhiyun set_dor(1, ~8, 0);
4972*4882a593Smuzhiyun #endif
4973*4882a593Smuzhiyun
4974*4882a593Smuzhiyun if (floppy_track_buffer && max_buffer_sectors) {
4975*4882a593Smuzhiyun tmpsize = max_buffer_sectors * 1024;
4976*4882a593Smuzhiyun tmpaddr = (unsigned long)floppy_track_buffer;
4977*4882a593Smuzhiyun floppy_track_buffer = NULL;
4978*4882a593Smuzhiyun max_buffer_sectors = 0;
4979*4882a593Smuzhiyun buffer_min = buffer_max = -1;
4980*4882a593Smuzhiyun fd_dma_mem_free(tmpaddr, tmpsize);
4981*4882a593Smuzhiyun }
4982*4882a593Smuzhiyun #ifndef __sparc__
4983*4882a593Smuzhiyun for (drive = 0; drive < N_FDC * 4; drive++)
4984*4882a593Smuzhiyun if (timer_pending(motor_off_timer + drive))
4985*4882a593Smuzhiyun pr_info("motor off timer %d still active\n", drive);
4986*4882a593Smuzhiyun #endif
4987*4882a593Smuzhiyun
4988*4882a593Smuzhiyun if (delayed_work_pending(&fd_timeout))
4989*4882a593Smuzhiyun pr_info("floppy timer still active:%s\n", timeout_message);
4990*4882a593Smuzhiyun if (delayed_work_pending(&fd_timer))
4991*4882a593Smuzhiyun pr_info("auxiliary floppy timer still active\n");
4992*4882a593Smuzhiyun if (work_pending(&floppy_work))
4993*4882a593Smuzhiyun pr_info("work still pending\n");
4994*4882a593Smuzhiyun for (fdc = 0; fdc < N_FDC; fdc++)
4995*4882a593Smuzhiyun if (fdc_state[fdc].address != -1)
4996*4882a593Smuzhiyun floppy_release_regions(fdc);
4997*4882a593Smuzhiyun }
4998*4882a593Smuzhiyun
4999*4882a593Smuzhiyun #ifdef MODULE
5000*4882a593Smuzhiyun
5001*4882a593Smuzhiyun static char *floppy;
5002*4882a593Smuzhiyun
parse_floppy_cfg_string(char * cfg)5003*4882a593Smuzhiyun static void __init parse_floppy_cfg_string(char *cfg)
5004*4882a593Smuzhiyun {
5005*4882a593Smuzhiyun char *ptr;
5006*4882a593Smuzhiyun
5007*4882a593Smuzhiyun while (*cfg) {
5008*4882a593Smuzhiyun ptr = cfg;
5009*4882a593Smuzhiyun while (*cfg && *cfg != ' ' && *cfg != '\t')
5010*4882a593Smuzhiyun cfg++;
5011*4882a593Smuzhiyun if (*cfg) {
5012*4882a593Smuzhiyun *cfg = '\0';
5013*4882a593Smuzhiyun cfg++;
5014*4882a593Smuzhiyun }
5015*4882a593Smuzhiyun if (*ptr)
5016*4882a593Smuzhiyun floppy_setup(ptr);
5017*4882a593Smuzhiyun }
5018*4882a593Smuzhiyun }
5019*4882a593Smuzhiyun
floppy_module_init(void)5020*4882a593Smuzhiyun static int __init floppy_module_init(void)
5021*4882a593Smuzhiyun {
5022*4882a593Smuzhiyun if (floppy)
5023*4882a593Smuzhiyun parse_floppy_cfg_string(floppy);
5024*4882a593Smuzhiyun return floppy_init();
5025*4882a593Smuzhiyun }
5026*4882a593Smuzhiyun module_init(floppy_module_init);
5027*4882a593Smuzhiyun
floppy_module_exit(void)5028*4882a593Smuzhiyun static void __exit floppy_module_exit(void)
5029*4882a593Smuzhiyun {
5030*4882a593Smuzhiyun int drive;
5031*4882a593Smuzhiyun
5032*4882a593Smuzhiyun blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
5033*4882a593Smuzhiyun unregister_blkdev(FLOPPY_MAJOR, "fd");
5034*4882a593Smuzhiyun platform_driver_unregister(&floppy_driver);
5035*4882a593Smuzhiyun
5036*4882a593Smuzhiyun destroy_workqueue(floppy_wq);
5037*4882a593Smuzhiyun
5038*4882a593Smuzhiyun for (drive = 0; drive < N_DRIVE; drive++) {
5039*4882a593Smuzhiyun del_timer_sync(&motor_off_timer[drive]);
5040*4882a593Smuzhiyun
5041*4882a593Smuzhiyun if (floppy_available(drive)) {
5042*4882a593Smuzhiyun del_gendisk(disks[drive]);
5043*4882a593Smuzhiyun platform_device_unregister(&floppy_device[drive]);
5044*4882a593Smuzhiyun }
5045*4882a593Smuzhiyun blk_cleanup_queue(disks[drive]->queue);
5046*4882a593Smuzhiyun blk_mq_free_tag_set(&tag_sets[drive]);
5047*4882a593Smuzhiyun
5048*4882a593Smuzhiyun /*
5049*4882a593Smuzhiyun * These disks have not called add_disk(). Don't put down
5050*4882a593Smuzhiyun * queue reference in put_disk().
5051*4882a593Smuzhiyun */
5052*4882a593Smuzhiyun if (!(allowed_drive_mask & (1 << drive)) ||
5053*4882a593Smuzhiyun fdc_state[FDC(drive)].version == FDC_NONE)
5054*4882a593Smuzhiyun disks[drive]->queue = NULL;
5055*4882a593Smuzhiyun
5056*4882a593Smuzhiyun put_disk(disks[drive]);
5057*4882a593Smuzhiyun }
5058*4882a593Smuzhiyun
5059*4882a593Smuzhiyun cancel_delayed_work_sync(&fd_timeout);
5060*4882a593Smuzhiyun cancel_delayed_work_sync(&fd_timer);
5061*4882a593Smuzhiyun
5062*4882a593Smuzhiyun if (atomic_read(&usage_count))
5063*4882a593Smuzhiyun floppy_release_irq_and_dma();
5064*4882a593Smuzhiyun
5065*4882a593Smuzhiyun /* eject disk, if any */
5066*4882a593Smuzhiyun fd_eject(0);
5067*4882a593Smuzhiyun }
5068*4882a593Smuzhiyun
5069*4882a593Smuzhiyun module_exit(floppy_module_exit);
5070*4882a593Smuzhiyun
5071*4882a593Smuzhiyun module_param(floppy, charp, 0);
5072*4882a593Smuzhiyun module_param(FLOPPY_IRQ, int, 0);
5073*4882a593Smuzhiyun module_param(FLOPPY_DMA, int, 0);
5074*4882a593Smuzhiyun MODULE_AUTHOR("Alain L. Knaff");
5075*4882a593Smuzhiyun MODULE_SUPPORTED_DEVICE("fd");
5076*4882a593Smuzhiyun MODULE_LICENSE("GPL");
5077*4882a593Smuzhiyun
5078*4882a593Smuzhiyun /* This doesn't actually get used other than for module information */
5079*4882a593Smuzhiyun static const struct pnp_device_id floppy_pnpids[] = {
5080*4882a593Smuzhiyun {"PNP0700", 0},
5081*4882a593Smuzhiyun {}
5082*4882a593Smuzhiyun };
5083*4882a593Smuzhiyun
5084*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pnp, floppy_pnpids);
5085*4882a593Smuzhiyun
5086*4882a593Smuzhiyun #else
5087*4882a593Smuzhiyun
5088*4882a593Smuzhiyun __setup("floppy=", floppy_setup);
5089*4882a593Smuzhiyun module_init(floppy_init)
5090*4882a593Smuzhiyun #endif
5091*4882a593Smuzhiyun
5092*4882a593Smuzhiyun MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);
5093