xref: /openbmc/linux/drivers/block/swim3.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /*
2*1da177e4SLinus Torvalds  * Driver for the SWIM3 (Super Woz Integrated Machine 3)
3*1da177e4SLinus Torvalds  * floppy controller found on Power Macintoshes.
4*1da177e4SLinus Torvalds  *
5*1da177e4SLinus Torvalds  * Copyright (C) 1996 Paul Mackerras.
6*1da177e4SLinus Torvalds  *
7*1da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or
8*1da177e4SLinus Torvalds  * modify it under the terms of the GNU General Public License
9*1da177e4SLinus Torvalds  * as published by the Free Software Foundation; either version
10*1da177e4SLinus Torvalds  * 2 of the License, or (at your option) any later version.
11*1da177e4SLinus Torvalds  */
12*1da177e4SLinus Torvalds 
13*1da177e4SLinus Torvalds /*
14*1da177e4SLinus Torvalds  * TODO:
15*1da177e4SLinus Torvalds  * handle 2 drives
16*1da177e4SLinus Torvalds  * handle GCR disks
17*1da177e4SLinus Torvalds  */
18*1da177e4SLinus Torvalds 
19*1da177e4SLinus Torvalds #include <linux/config.h>
20*1da177e4SLinus Torvalds #include <linux/stddef.h>
21*1da177e4SLinus Torvalds #include <linux/kernel.h>
22*1da177e4SLinus Torvalds #include <linux/sched.h>
23*1da177e4SLinus Torvalds #include <linux/timer.h>
24*1da177e4SLinus Torvalds #include <linux/delay.h>
25*1da177e4SLinus Torvalds #include <linux/fd.h>
26*1da177e4SLinus Torvalds #include <linux/ioctl.h>
27*1da177e4SLinus Torvalds #include <linux/blkdev.h>
28*1da177e4SLinus Torvalds #include <linux/devfs_fs_kernel.h>
29*1da177e4SLinus Torvalds #include <linux/interrupt.h>
30*1da177e4SLinus Torvalds #include <linux/module.h>
31*1da177e4SLinus Torvalds #include <asm/io.h>
32*1da177e4SLinus Torvalds #include <asm/dbdma.h>
33*1da177e4SLinus Torvalds #include <asm/prom.h>
34*1da177e4SLinus Torvalds #include <asm/uaccess.h>
35*1da177e4SLinus Torvalds #include <asm/mediabay.h>
36*1da177e4SLinus Torvalds #include <asm/machdep.h>
37*1da177e4SLinus Torvalds #include <asm/pmac_feature.h>
38*1da177e4SLinus Torvalds 
39*1da177e4SLinus Torvalds static struct request_queue *swim3_queue;
40*1da177e4SLinus Torvalds static struct gendisk *disks[2];
41*1da177e4SLinus Torvalds static struct request *fd_req;
42*1da177e4SLinus Torvalds 
43*1da177e4SLinus Torvalds #define MAX_FLOPPIES	2
44*1da177e4SLinus Torvalds 
45*1da177e4SLinus Torvalds enum swim_state {
46*1da177e4SLinus Torvalds 	idle,
47*1da177e4SLinus Torvalds 	locating,
48*1da177e4SLinus Torvalds 	seeking,
49*1da177e4SLinus Torvalds 	settling,
50*1da177e4SLinus Torvalds 	do_transfer,
51*1da177e4SLinus Torvalds 	jogging,
52*1da177e4SLinus Torvalds 	available,
53*1da177e4SLinus Torvalds 	revalidating,
54*1da177e4SLinus Torvalds 	ejecting
55*1da177e4SLinus Torvalds };
56*1da177e4SLinus Torvalds 
57*1da177e4SLinus Torvalds #define REG(x)	unsigned char x; char x ## _pad[15];
58*1da177e4SLinus Torvalds 
59*1da177e4SLinus Torvalds /*
60*1da177e4SLinus Torvalds  * The names for these registers mostly represent speculation on my part.
61*1da177e4SLinus Torvalds  * It will be interesting to see how close they are to the names Apple uses.
62*1da177e4SLinus Torvalds  */
63*1da177e4SLinus Torvalds struct swim3 {
64*1da177e4SLinus Torvalds 	REG(data);
65*1da177e4SLinus Torvalds 	REG(timer);		/* counts down at 1MHz */
66*1da177e4SLinus Torvalds 	REG(error);
67*1da177e4SLinus Torvalds 	REG(mode);
68*1da177e4SLinus Torvalds 	REG(select);		/* controls CA0, CA1, CA2 and LSTRB signals */
69*1da177e4SLinus Torvalds 	REG(setup);
70*1da177e4SLinus Torvalds 	REG(control);		/* writing bits clears them */
71*1da177e4SLinus Torvalds 	REG(status);		/* writing bits sets them in control */
72*1da177e4SLinus Torvalds 	REG(intr);
73*1da177e4SLinus Torvalds 	REG(nseek);		/* # tracks to seek */
74*1da177e4SLinus Torvalds 	REG(ctrack);		/* current track number */
75*1da177e4SLinus Torvalds 	REG(csect);		/* current sector number */
76*1da177e4SLinus Torvalds 	REG(gap3);		/* size of gap 3 in track format */
77*1da177e4SLinus Torvalds 	REG(sector);		/* sector # to read or write */
78*1da177e4SLinus Torvalds 	REG(nsect);		/* # sectors to read or write */
79*1da177e4SLinus Torvalds 	REG(intr_enable);
80*1da177e4SLinus Torvalds };
81*1da177e4SLinus Torvalds 
82*1da177e4SLinus Torvalds #define control_bic	control
83*1da177e4SLinus Torvalds #define control_bis	status
84*1da177e4SLinus Torvalds 
85*1da177e4SLinus Torvalds /* Bits in select register */
86*1da177e4SLinus Torvalds #define CA_MASK		7
87*1da177e4SLinus Torvalds #define LSTRB		8
88*1da177e4SLinus Torvalds 
89*1da177e4SLinus Torvalds /* Bits in control register */
90*1da177e4SLinus Torvalds #define DO_SEEK		0x80
91*1da177e4SLinus Torvalds #define FORMAT		0x40
92*1da177e4SLinus Torvalds #define SELECT		0x20
93*1da177e4SLinus Torvalds #define WRITE_SECTORS	0x10
94*1da177e4SLinus Torvalds #define DO_ACTION	0x08
95*1da177e4SLinus Torvalds #define DRIVE2_ENABLE	0x04
96*1da177e4SLinus Torvalds #define DRIVE_ENABLE	0x02
97*1da177e4SLinus Torvalds #define INTR_ENABLE	0x01
98*1da177e4SLinus Torvalds 
99*1da177e4SLinus Torvalds /* Bits in status register */
100*1da177e4SLinus Torvalds #define FIFO_1BYTE	0x80
101*1da177e4SLinus Torvalds #define FIFO_2BYTE	0x40
102*1da177e4SLinus Torvalds #define ERROR		0x20
103*1da177e4SLinus Torvalds #define DATA		0x08
104*1da177e4SLinus Torvalds #define RDDATA		0x04
105*1da177e4SLinus Torvalds #define INTR_PENDING	0x02
106*1da177e4SLinus Torvalds #define MARK_BYTE	0x01
107*1da177e4SLinus Torvalds 
108*1da177e4SLinus Torvalds /* Bits in intr and intr_enable registers */
109*1da177e4SLinus Torvalds #define ERROR_INTR	0x20
110*1da177e4SLinus Torvalds #define DATA_CHANGED	0x10
111*1da177e4SLinus Torvalds #define TRANSFER_DONE	0x08
112*1da177e4SLinus Torvalds #define SEEN_SECTOR	0x04
113*1da177e4SLinus Torvalds #define SEEK_DONE	0x02
114*1da177e4SLinus Torvalds #define TIMER_DONE	0x01
115*1da177e4SLinus Torvalds 
116*1da177e4SLinus Torvalds /* Bits in error register */
117*1da177e4SLinus Torvalds #define ERR_DATA_CRC	0x80
118*1da177e4SLinus Torvalds #define ERR_ADDR_CRC	0x40
119*1da177e4SLinus Torvalds #define ERR_OVERRUN	0x04
120*1da177e4SLinus Torvalds #define ERR_UNDERRUN	0x01
121*1da177e4SLinus Torvalds 
122*1da177e4SLinus Torvalds /* Bits in setup register */
123*1da177e4SLinus Torvalds #define S_SW_RESET	0x80
124*1da177e4SLinus Torvalds #define S_GCR_WRITE	0x40
125*1da177e4SLinus Torvalds #define S_IBM_DRIVE	0x20
126*1da177e4SLinus Torvalds #define S_TEST_MODE	0x10
127*1da177e4SLinus Torvalds #define S_FCLK_DIV2	0x08
128*1da177e4SLinus Torvalds #define S_GCR		0x04
129*1da177e4SLinus Torvalds #define S_COPY_PROT	0x02
130*1da177e4SLinus Torvalds #define S_INV_WDATA	0x01
131*1da177e4SLinus Torvalds 
132*1da177e4SLinus Torvalds /* Select values for swim3_action */
133*1da177e4SLinus Torvalds #define SEEK_POSITIVE	0
134*1da177e4SLinus Torvalds #define SEEK_NEGATIVE	4
135*1da177e4SLinus Torvalds #define STEP		1
136*1da177e4SLinus Torvalds #define MOTOR_ON	2
137*1da177e4SLinus Torvalds #define MOTOR_OFF	6
138*1da177e4SLinus Torvalds #define INDEX		3
139*1da177e4SLinus Torvalds #define EJECT		7
140*1da177e4SLinus Torvalds #define SETMFM		9
141*1da177e4SLinus Torvalds #define SETGCR		13
142*1da177e4SLinus Torvalds 
143*1da177e4SLinus Torvalds /* Select values for swim3_select and swim3_readbit */
144*1da177e4SLinus Torvalds #define STEP_DIR	0
145*1da177e4SLinus Torvalds #define STEPPING	1
146*1da177e4SLinus Torvalds #define MOTOR_ON	2
147*1da177e4SLinus Torvalds #define RELAX		3	/* also eject in progress */
148*1da177e4SLinus Torvalds #define READ_DATA_0	4
149*1da177e4SLinus Torvalds #define TWOMEG_DRIVE	5
150*1da177e4SLinus Torvalds #define SINGLE_SIDED	6	/* drive or diskette is 4MB type? */
151*1da177e4SLinus Torvalds #define DRIVE_PRESENT	7
152*1da177e4SLinus Torvalds #define DISK_IN		8
153*1da177e4SLinus Torvalds #define WRITE_PROT	9
154*1da177e4SLinus Torvalds #define TRACK_ZERO	10
155*1da177e4SLinus Torvalds #define TACHO		11
156*1da177e4SLinus Torvalds #define READ_DATA_1	12
157*1da177e4SLinus Torvalds #define MFM_MODE	13
158*1da177e4SLinus Torvalds #define SEEK_COMPLETE	14
159*1da177e4SLinus Torvalds #define ONEMEG_MEDIA	15
160*1da177e4SLinus Torvalds 
161*1da177e4SLinus Torvalds /* Definitions of values used in writing and formatting */
162*1da177e4SLinus Torvalds #define DATA_ESCAPE	0x99
163*1da177e4SLinus Torvalds #define GCR_SYNC_EXC	0x3f
164*1da177e4SLinus Torvalds #define GCR_SYNC_CONV	0x80
165*1da177e4SLinus Torvalds #define GCR_FIRST_MARK	0xd5
166*1da177e4SLinus Torvalds #define GCR_SECOND_MARK	0xaa
167*1da177e4SLinus Torvalds #define GCR_ADDR_MARK	"\xd5\xaa\x00"
168*1da177e4SLinus Torvalds #define GCR_DATA_MARK	"\xd5\xaa\x0b"
169*1da177e4SLinus Torvalds #define GCR_SLIP_BYTE	"\x27\xaa"
170*1da177e4SLinus Torvalds #define GCR_SELF_SYNC	"\x3f\xbf\x1e\x34\x3c\x3f"
171*1da177e4SLinus Torvalds 
172*1da177e4SLinus Torvalds #define DATA_99		"\x99\x99"
173*1da177e4SLinus Torvalds #define MFM_ADDR_MARK	"\x99\xa1\x99\xa1\x99\xa1\x99\xfe"
174*1da177e4SLinus Torvalds #define MFM_INDEX_MARK	"\x99\xc2\x99\xc2\x99\xc2\x99\xfc"
175*1da177e4SLinus Torvalds #define MFM_GAP_LEN	12
176*1da177e4SLinus Torvalds 
177*1da177e4SLinus Torvalds struct floppy_state {
178*1da177e4SLinus Torvalds 	enum swim_state	state;
179*1da177e4SLinus Torvalds 	struct swim3 __iomem *swim3;	/* hardware registers */
180*1da177e4SLinus Torvalds 	struct dbdma_regs __iomem *dma;	/* DMA controller registers */
181*1da177e4SLinus Torvalds 	int	swim3_intr;	/* interrupt number for SWIM3 */
182*1da177e4SLinus Torvalds 	int	dma_intr;	/* interrupt number for DMA channel */
183*1da177e4SLinus Torvalds 	int	cur_cyl;	/* cylinder head is on, or -1 */
184*1da177e4SLinus Torvalds 	int	cur_sector;	/* last sector we saw go past */
185*1da177e4SLinus Torvalds 	int	req_cyl;	/* the cylinder for the current r/w request */
186*1da177e4SLinus Torvalds 	int	head;		/* head number ditto */
187*1da177e4SLinus Torvalds 	int	req_sector;	/* sector number ditto */
188*1da177e4SLinus Torvalds 	int	scount;		/* # sectors we're transferring at present */
189*1da177e4SLinus Torvalds 	int	retries;
190*1da177e4SLinus Torvalds 	int	settle_time;
191*1da177e4SLinus Torvalds 	int	secpercyl;	/* disk geometry information */
192*1da177e4SLinus Torvalds 	int	secpertrack;
193*1da177e4SLinus Torvalds 	int	total_secs;
194*1da177e4SLinus Torvalds 	int	write_prot;	/* 1 if write-protected, 0 if not, -1 dunno */
195*1da177e4SLinus Torvalds 	struct dbdma_cmd *dma_cmd;
196*1da177e4SLinus Torvalds 	int	ref_count;
197*1da177e4SLinus Torvalds 	int	expect_cyl;
198*1da177e4SLinus Torvalds 	struct timer_list timeout;
199*1da177e4SLinus Torvalds 	int	timeout_pending;
200*1da177e4SLinus Torvalds 	int	ejected;
201*1da177e4SLinus Torvalds 	wait_queue_head_t wait;
202*1da177e4SLinus Torvalds 	int	wanted;
203*1da177e4SLinus Torvalds 	struct device_node*	media_bay; /* NULL when not in bay */
204*1da177e4SLinus Torvalds 	char	dbdma_cmd_space[5 * sizeof(struct dbdma_cmd)];
205*1da177e4SLinus Torvalds };
206*1da177e4SLinus Torvalds 
207*1da177e4SLinus Torvalds static struct floppy_state floppy_states[MAX_FLOPPIES];
208*1da177e4SLinus Torvalds static int floppy_count = 0;
209*1da177e4SLinus Torvalds static DEFINE_SPINLOCK(swim3_lock);
210*1da177e4SLinus Torvalds 
211*1da177e4SLinus Torvalds static unsigned short write_preamble[] = {
212*1da177e4SLinus Torvalds 	0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e,	/* gap field */
213*1da177e4SLinus Torvalds 	0, 0, 0, 0, 0, 0,			/* sync field */
214*1da177e4SLinus Torvalds 	0x99a1, 0x99a1, 0x99a1, 0x99fb,		/* data address mark */
215*1da177e4SLinus Torvalds 	0x990f					/* no escape for 512 bytes */
216*1da177e4SLinus Torvalds };
217*1da177e4SLinus Torvalds 
218*1da177e4SLinus Torvalds static unsigned short write_postamble[] = {
219*1da177e4SLinus Torvalds 	0x9904,					/* insert CRC */
220*1da177e4SLinus Torvalds 	0x4e4e, 0x4e4e,
221*1da177e4SLinus Torvalds 	0x9908,					/* stop writing */
222*1da177e4SLinus Torvalds 	0, 0, 0, 0, 0, 0
223*1da177e4SLinus Torvalds };
224*1da177e4SLinus Torvalds 
225*1da177e4SLinus Torvalds static void swim3_select(struct floppy_state *fs, int sel);
226*1da177e4SLinus Torvalds static void swim3_action(struct floppy_state *fs, int action);
227*1da177e4SLinus Torvalds static int swim3_readbit(struct floppy_state *fs, int bit);
228*1da177e4SLinus Torvalds static void do_fd_request(request_queue_t * q);
229*1da177e4SLinus Torvalds static void start_request(struct floppy_state *fs);
230*1da177e4SLinus Torvalds static void set_timeout(struct floppy_state *fs, int nticks,
231*1da177e4SLinus Torvalds 			void (*proc)(unsigned long));
232*1da177e4SLinus Torvalds static void scan_track(struct floppy_state *fs);
233*1da177e4SLinus Torvalds static void seek_track(struct floppy_state *fs, int n);
234*1da177e4SLinus Torvalds static void init_dma(struct dbdma_cmd *cp, int cmd, void *buf, int count);
235*1da177e4SLinus Torvalds static void setup_transfer(struct floppy_state *fs);
236*1da177e4SLinus Torvalds static void act(struct floppy_state *fs);
237*1da177e4SLinus Torvalds static void scan_timeout(unsigned long data);
238*1da177e4SLinus Torvalds static void seek_timeout(unsigned long data);
239*1da177e4SLinus Torvalds static void settle_timeout(unsigned long data);
240*1da177e4SLinus Torvalds static void xfer_timeout(unsigned long data);
241*1da177e4SLinus Torvalds static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
242*1da177e4SLinus Torvalds /*static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs);*/
243*1da177e4SLinus Torvalds static int grab_drive(struct floppy_state *fs, enum swim_state state,
244*1da177e4SLinus Torvalds 		      int interruptible);
245*1da177e4SLinus Torvalds static void release_drive(struct floppy_state *fs);
246*1da177e4SLinus Torvalds static int fd_eject(struct floppy_state *fs);
247*1da177e4SLinus Torvalds static int floppy_ioctl(struct inode *inode, struct file *filp,
248*1da177e4SLinus Torvalds 			unsigned int cmd, unsigned long param);
249*1da177e4SLinus Torvalds static int floppy_open(struct inode *inode, struct file *filp);
250*1da177e4SLinus Torvalds static int floppy_release(struct inode *inode, struct file *filp);
251*1da177e4SLinus Torvalds static int floppy_check_change(struct gendisk *disk);
252*1da177e4SLinus Torvalds static int floppy_revalidate(struct gendisk *disk);
253*1da177e4SLinus Torvalds static int swim3_add_device(struct device_node *swims);
254*1da177e4SLinus Torvalds int swim3_init(void);
255*1da177e4SLinus Torvalds 
256*1da177e4SLinus Torvalds #ifndef CONFIG_PMAC_PBOOK
257*1da177e4SLinus Torvalds #define check_media_bay(which, what)	1
258*1da177e4SLinus Torvalds #endif
259*1da177e4SLinus Torvalds 
260*1da177e4SLinus Torvalds static void swim3_select(struct floppy_state *fs, int sel)
261*1da177e4SLinus Torvalds {
262*1da177e4SLinus Torvalds 	struct swim3 __iomem *sw = fs->swim3;
263*1da177e4SLinus Torvalds 
264*1da177e4SLinus Torvalds 	out_8(&sw->select, RELAX);
265*1da177e4SLinus Torvalds 	if (sel & 8)
266*1da177e4SLinus Torvalds 		out_8(&sw->control_bis, SELECT);
267*1da177e4SLinus Torvalds 	else
268*1da177e4SLinus Torvalds 		out_8(&sw->control_bic, SELECT);
269*1da177e4SLinus Torvalds 	out_8(&sw->select, sel & CA_MASK);
270*1da177e4SLinus Torvalds }
271*1da177e4SLinus Torvalds 
272*1da177e4SLinus Torvalds static void swim3_action(struct floppy_state *fs, int action)
273*1da177e4SLinus Torvalds {
274*1da177e4SLinus Torvalds 	struct swim3 __iomem *sw = fs->swim3;
275*1da177e4SLinus Torvalds 
276*1da177e4SLinus Torvalds 	swim3_select(fs, action);
277*1da177e4SLinus Torvalds 	udelay(1);
278*1da177e4SLinus Torvalds 	out_8(&sw->select, sw->select | LSTRB);
279*1da177e4SLinus Torvalds 	udelay(2);
280*1da177e4SLinus Torvalds 	out_8(&sw->select, sw->select & ~LSTRB);
281*1da177e4SLinus Torvalds 	udelay(1);
282*1da177e4SLinus Torvalds }
283*1da177e4SLinus Torvalds 
284*1da177e4SLinus Torvalds static int swim3_readbit(struct floppy_state *fs, int bit)
285*1da177e4SLinus Torvalds {
286*1da177e4SLinus Torvalds 	struct swim3 __iomem *sw = fs->swim3;
287*1da177e4SLinus Torvalds 	int stat;
288*1da177e4SLinus Torvalds 
289*1da177e4SLinus Torvalds 	swim3_select(fs, bit);
290*1da177e4SLinus Torvalds 	udelay(1);
291*1da177e4SLinus Torvalds 	stat = in_8(&sw->status);
292*1da177e4SLinus Torvalds 	return (stat & DATA) == 0;
293*1da177e4SLinus Torvalds }
294*1da177e4SLinus Torvalds 
295*1da177e4SLinus Torvalds static void do_fd_request(request_queue_t * q)
296*1da177e4SLinus Torvalds {
297*1da177e4SLinus Torvalds 	int i;
298*1da177e4SLinus Torvalds 	for(i=0;i<floppy_count;i++)
299*1da177e4SLinus Torvalds 	{
300*1da177e4SLinus Torvalds 		if (floppy_states[i].media_bay &&
301*1da177e4SLinus Torvalds 			check_media_bay(floppy_states[i].media_bay, MB_FD))
302*1da177e4SLinus Torvalds 			continue;
303*1da177e4SLinus Torvalds 		start_request(&floppy_states[i]);
304*1da177e4SLinus Torvalds 	}
305*1da177e4SLinus Torvalds 	sti();
306*1da177e4SLinus Torvalds }
307*1da177e4SLinus Torvalds 
308*1da177e4SLinus Torvalds static void start_request(struct floppy_state *fs)
309*1da177e4SLinus Torvalds {
310*1da177e4SLinus Torvalds 	struct request *req;
311*1da177e4SLinus Torvalds 	unsigned long x;
312*1da177e4SLinus Torvalds 
313*1da177e4SLinus Torvalds 	if (fs->state == idle && fs->wanted) {
314*1da177e4SLinus Torvalds 		fs->state = available;
315*1da177e4SLinus Torvalds 		wake_up(&fs->wait);
316*1da177e4SLinus Torvalds 		return;
317*1da177e4SLinus Torvalds 	}
318*1da177e4SLinus Torvalds 	while (fs->state == idle && (req = elv_next_request(swim3_queue))) {
319*1da177e4SLinus Torvalds #if 0
320*1da177e4SLinus Torvalds 		printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%ld buf=%p\n",
321*1da177e4SLinus Torvalds 		       req->rq_disk->disk_name, req->cmd,
322*1da177e4SLinus Torvalds 		       (long)req->sector, req->nr_sectors, req->buffer);
323*1da177e4SLinus Torvalds 		printk("           rq_status=%d errors=%d current_nr_sectors=%ld\n",
324*1da177e4SLinus Torvalds 		       req->rq_status, req->errors, req->current_nr_sectors);
325*1da177e4SLinus Torvalds #endif
326*1da177e4SLinus Torvalds 
327*1da177e4SLinus Torvalds 		if (req->sector < 0 || req->sector >= fs->total_secs) {
328*1da177e4SLinus Torvalds 			end_request(req, 0);
329*1da177e4SLinus Torvalds 			continue;
330*1da177e4SLinus Torvalds 		}
331*1da177e4SLinus Torvalds 		if (req->current_nr_sectors == 0) {
332*1da177e4SLinus Torvalds 			end_request(req, 1);
333*1da177e4SLinus Torvalds 			continue;
334*1da177e4SLinus Torvalds 		}
335*1da177e4SLinus Torvalds 		if (fs->ejected) {
336*1da177e4SLinus Torvalds 			end_request(req, 0);
337*1da177e4SLinus Torvalds 			continue;
338*1da177e4SLinus Torvalds 		}
339*1da177e4SLinus Torvalds 
340*1da177e4SLinus Torvalds 		if (rq_data_dir(req) == WRITE) {
341*1da177e4SLinus Torvalds 			if (fs->write_prot < 0)
342*1da177e4SLinus Torvalds 				fs->write_prot = swim3_readbit(fs, WRITE_PROT);
343*1da177e4SLinus Torvalds 			if (fs->write_prot) {
344*1da177e4SLinus Torvalds 				end_request(req, 0);
345*1da177e4SLinus Torvalds 				continue;
346*1da177e4SLinus Torvalds 			}
347*1da177e4SLinus Torvalds 		}
348*1da177e4SLinus Torvalds 
349*1da177e4SLinus Torvalds 		/* Do not remove the cast. req->sector is now a sector_t and
350*1da177e4SLinus Torvalds 		 * can be 64 bits, but it will never go past 32 bits for this
351*1da177e4SLinus Torvalds 		 * driver anyway, so we can safely cast it down and not have
352*1da177e4SLinus Torvalds 		 * to do a 64/32 division
353*1da177e4SLinus Torvalds 		 */
354*1da177e4SLinus Torvalds 		fs->req_cyl = ((long)req->sector) / fs->secpercyl;
355*1da177e4SLinus Torvalds 		x = ((long)req->sector) % fs->secpercyl;
356*1da177e4SLinus Torvalds 		fs->head = x / fs->secpertrack;
357*1da177e4SLinus Torvalds 		fs->req_sector = x % fs->secpertrack + 1;
358*1da177e4SLinus Torvalds 		fd_req = req;
359*1da177e4SLinus Torvalds 		fs->state = do_transfer;
360*1da177e4SLinus Torvalds 		fs->retries = 0;
361*1da177e4SLinus Torvalds 
362*1da177e4SLinus Torvalds 		act(fs);
363*1da177e4SLinus Torvalds 	}
364*1da177e4SLinus Torvalds }
365*1da177e4SLinus Torvalds 
366*1da177e4SLinus Torvalds static void set_timeout(struct floppy_state *fs, int nticks,
367*1da177e4SLinus Torvalds 			void (*proc)(unsigned long))
368*1da177e4SLinus Torvalds {
369*1da177e4SLinus Torvalds 	unsigned long flags;
370*1da177e4SLinus Torvalds 
371*1da177e4SLinus Torvalds 	save_flags(flags); cli();
372*1da177e4SLinus Torvalds 	if (fs->timeout_pending)
373*1da177e4SLinus Torvalds 		del_timer(&fs->timeout);
374*1da177e4SLinus Torvalds 	fs->timeout.expires = jiffies + nticks;
375*1da177e4SLinus Torvalds 	fs->timeout.function = proc;
376*1da177e4SLinus Torvalds 	fs->timeout.data = (unsigned long) fs;
377*1da177e4SLinus Torvalds 	add_timer(&fs->timeout);
378*1da177e4SLinus Torvalds 	fs->timeout_pending = 1;
379*1da177e4SLinus Torvalds 	restore_flags(flags);
380*1da177e4SLinus Torvalds }
381*1da177e4SLinus Torvalds 
382*1da177e4SLinus Torvalds static inline void scan_track(struct floppy_state *fs)
383*1da177e4SLinus Torvalds {
384*1da177e4SLinus Torvalds 	struct swim3 __iomem *sw = fs->swim3;
385*1da177e4SLinus Torvalds 
386*1da177e4SLinus Torvalds 	swim3_select(fs, READ_DATA_0);
387*1da177e4SLinus Torvalds 	in_8(&sw->intr);		/* clear SEEN_SECTOR bit */
388*1da177e4SLinus Torvalds 	in_8(&sw->error);
389*1da177e4SLinus Torvalds 	out_8(&sw->intr_enable, SEEN_SECTOR);
390*1da177e4SLinus Torvalds 	out_8(&sw->control_bis, DO_ACTION);
391*1da177e4SLinus Torvalds 	/* enable intr when track found */
392*1da177e4SLinus Torvalds 	set_timeout(fs, HZ, scan_timeout);	/* enable timeout */
393*1da177e4SLinus Torvalds }
394*1da177e4SLinus Torvalds 
395*1da177e4SLinus Torvalds static inline void seek_track(struct floppy_state *fs, int n)
396*1da177e4SLinus Torvalds {
397*1da177e4SLinus Torvalds 	struct swim3 __iomem *sw = fs->swim3;
398*1da177e4SLinus Torvalds 
399*1da177e4SLinus Torvalds 	if (n >= 0) {
400*1da177e4SLinus Torvalds 		swim3_action(fs, SEEK_POSITIVE);
401*1da177e4SLinus Torvalds 		sw->nseek = n;
402*1da177e4SLinus Torvalds 	} else {
403*1da177e4SLinus Torvalds 		swim3_action(fs, SEEK_NEGATIVE);
404*1da177e4SLinus Torvalds 		sw->nseek = -n;
405*1da177e4SLinus Torvalds 	}
406*1da177e4SLinus Torvalds 	fs->expect_cyl = (fs->cur_cyl >= 0)? fs->cur_cyl + n: -1;
407*1da177e4SLinus Torvalds 	swim3_select(fs, STEP);
408*1da177e4SLinus Torvalds 	in_8(&sw->error);
409*1da177e4SLinus Torvalds 	/* enable intr when seek finished */
410*1da177e4SLinus Torvalds 	out_8(&sw->intr_enable, SEEK_DONE);
411*1da177e4SLinus Torvalds 	out_8(&sw->control_bis, DO_SEEK);
412*1da177e4SLinus Torvalds 	set_timeout(fs, 3*HZ, seek_timeout);	/* enable timeout */
413*1da177e4SLinus Torvalds 	fs->settle_time = 0;
414*1da177e4SLinus Torvalds }
415*1da177e4SLinus Torvalds 
416*1da177e4SLinus Torvalds static inline void init_dma(struct dbdma_cmd *cp, int cmd,
417*1da177e4SLinus Torvalds 			    void *buf, int count)
418*1da177e4SLinus Torvalds {
419*1da177e4SLinus Torvalds 	st_le16(&cp->req_count, count);
420*1da177e4SLinus Torvalds 	st_le16(&cp->command, cmd);
421*1da177e4SLinus Torvalds 	st_le32(&cp->phy_addr, virt_to_bus(buf));
422*1da177e4SLinus Torvalds 	cp->xfer_status = 0;
423*1da177e4SLinus Torvalds }
424*1da177e4SLinus Torvalds 
425*1da177e4SLinus Torvalds static inline void setup_transfer(struct floppy_state *fs)
426*1da177e4SLinus Torvalds {
427*1da177e4SLinus Torvalds 	int n;
428*1da177e4SLinus Torvalds 	struct swim3 __iomem *sw = fs->swim3;
429*1da177e4SLinus Torvalds 	struct dbdma_cmd *cp = fs->dma_cmd;
430*1da177e4SLinus Torvalds 	struct dbdma_regs __iomem *dr = fs->dma;
431*1da177e4SLinus Torvalds 
432*1da177e4SLinus Torvalds 	if (fd_req->current_nr_sectors <= 0) {
433*1da177e4SLinus Torvalds 		printk(KERN_ERR "swim3: transfer 0 sectors?\n");
434*1da177e4SLinus Torvalds 		return;
435*1da177e4SLinus Torvalds 	}
436*1da177e4SLinus Torvalds 	if (rq_data_dir(fd_req) == WRITE)
437*1da177e4SLinus Torvalds 		n = 1;
438*1da177e4SLinus Torvalds 	else {
439*1da177e4SLinus Torvalds 		n = fs->secpertrack - fs->req_sector + 1;
440*1da177e4SLinus Torvalds 		if (n > fd_req->current_nr_sectors)
441*1da177e4SLinus Torvalds 			n = fd_req->current_nr_sectors;
442*1da177e4SLinus Torvalds 	}
443*1da177e4SLinus Torvalds 	fs->scount = n;
444*1da177e4SLinus Torvalds 	swim3_select(fs, fs->head? READ_DATA_1: READ_DATA_0);
445*1da177e4SLinus Torvalds 	out_8(&sw->sector, fs->req_sector);
446*1da177e4SLinus Torvalds 	out_8(&sw->nsect, n);
447*1da177e4SLinus Torvalds 	out_8(&sw->gap3, 0);
448*1da177e4SLinus Torvalds 	out_le32(&dr->cmdptr, virt_to_bus(cp));
449*1da177e4SLinus Torvalds 	if (rq_data_dir(fd_req) == WRITE) {
450*1da177e4SLinus Torvalds 		/* Set up 3 dma commands: write preamble, data, postamble */
451*1da177e4SLinus Torvalds 		init_dma(cp, OUTPUT_MORE, write_preamble, sizeof(write_preamble));
452*1da177e4SLinus Torvalds 		++cp;
453*1da177e4SLinus Torvalds 		init_dma(cp, OUTPUT_MORE, fd_req->buffer, 512);
454*1da177e4SLinus Torvalds 		++cp;
455*1da177e4SLinus Torvalds 		init_dma(cp, OUTPUT_LAST, write_postamble, sizeof(write_postamble));
456*1da177e4SLinus Torvalds 	} else {
457*1da177e4SLinus Torvalds 		init_dma(cp, INPUT_LAST, fd_req->buffer, n * 512);
458*1da177e4SLinus Torvalds 	}
459*1da177e4SLinus Torvalds 	++cp;
460*1da177e4SLinus Torvalds 	out_le16(&cp->command, DBDMA_STOP);
461*1da177e4SLinus Torvalds 	out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS);
462*1da177e4SLinus Torvalds 	in_8(&sw->error);
463*1da177e4SLinus Torvalds 	out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS);
464*1da177e4SLinus Torvalds 	if (rq_data_dir(fd_req) == WRITE)
465*1da177e4SLinus Torvalds 		out_8(&sw->control_bis, WRITE_SECTORS);
466*1da177e4SLinus Torvalds 	in_8(&sw->intr);
467*1da177e4SLinus Torvalds 	out_le32(&dr->control, (RUN << 16) | RUN);
468*1da177e4SLinus Torvalds 	/* enable intr when transfer complete */
469*1da177e4SLinus Torvalds 	out_8(&sw->intr_enable, TRANSFER_DONE);
470*1da177e4SLinus Torvalds 	out_8(&sw->control_bis, DO_ACTION);
471*1da177e4SLinus Torvalds 	set_timeout(fs, 2*HZ, xfer_timeout);	/* enable timeout */
472*1da177e4SLinus Torvalds }
473*1da177e4SLinus Torvalds 
474*1da177e4SLinus Torvalds static void act(struct floppy_state *fs)
475*1da177e4SLinus Torvalds {
476*1da177e4SLinus Torvalds 	for (;;) {
477*1da177e4SLinus Torvalds 		switch (fs->state) {
478*1da177e4SLinus Torvalds 		case idle:
479*1da177e4SLinus Torvalds 			return;		/* XXX shouldn't get here */
480*1da177e4SLinus Torvalds 
481*1da177e4SLinus Torvalds 		case locating:
482*1da177e4SLinus Torvalds 			if (swim3_readbit(fs, TRACK_ZERO)) {
483*1da177e4SLinus Torvalds 				fs->cur_cyl = 0;
484*1da177e4SLinus Torvalds 				if (fs->req_cyl == 0)
485*1da177e4SLinus Torvalds 					fs->state = do_transfer;
486*1da177e4SLinus Torvalds 				else
487*1da177e4SLinus Torvalds 					fs->state = seeking;
488*1da177e4SLinus Torvalds 				break;
489*1da177e4SLinus Torvalds 			}
490*1da177e4SLinus Torvalds 			scan_track(fs);
491*1da177e4SLinus Torvalds 			return;
492*1da177e4SLinus Torvalds 
493*1da177e4SLinus Torvalds 		case seeking:
494*1da177e4SLinus Torvalds 			if (fs->cur_cyl < 0) {
495*1da177e4SLinus Torvalds 				fs->expect_cyl = -1;
496*1da177e4SLinus Torvalds 				fs->state = locating;
497*1da177e4SLinus Torvalds 				break;
498*1da177e4SLinus Torvalds 			}
499*1da177e4SLinus Torvalds 			if (fs->req_cyl == fs->cur_cyl) {
500*1da177e4SLinus Torvalds 				printk("whoops, seeking 0\n");
501*1da177e4SLinus Torvalds 				fs->state = do_transfer;
502*1da177e4SLinus Torvalds 				break;
503*1da177e4SLinus Torvalds 			}
504*1da177e4SLinus Torvalds 			seek_track(fs, fs->req_cyl - fs->cur_cyl);
505*1da177e4SLinus Torvalds 			return;
506*1da177e4SLinus Torvalds 
507*1da177e4SLinus Torvalds 		case settling:
508*1da177e4SLinus Torvalds 			/* check for SEEK_COMPLETE after 30ms */
509*1da177e4SLinus Torvalds 			fs->settle_time = (HZ + 32) / 33;
510*1da177e4SLinus Torvalds 			set_timeout(fs, fs->settle_time, settle_timeout);
511*1da177e4SLinus Torvalds 			return;
512*1da177e4SLinus Torvalds 
513*1da177e4SLinus Torvalds 		case do_transfer:
514*1da177e4SLinus Torvalds 			if (fs->cur_cyl != fs->req_cyl) {
515*1da177e4SLinus Torvalds 				if (fs->retries > 5) {
516*1da177e4SLinus Torvalds 					end_request(fd_req, 0);
517*1da177e4SLinus Torvalds 					fs->state = idle;
518*1da177e4SLinus Torvalds 					return;
519*1da177e4SLinus Torvalds 				}
520*1da177e4SLinus Torvalds 				fs->state = seeking;
521*1da177e4SLinus Torvalds 				break;
522*1da177e4SLinus Torvalds 			}
523*1da177e4SLinus Torvalds 			setup_transfer(fs);
524*1da177e4SLinus Torvalds 			return;
525*1da177e4SLinus Torvalds 
526*1da177e4SLinus Torvalds 		case jogging:
527*1da177e4SLinus Torvalds 			seek_track(fs, -5);
528*1da177e4SLinus Torvalds 			return;
529*1da177e4SLinus Torvalds 
530*1da177e4SLinus Torvalds 		default:
531*1da177e4SLinus Torvalds 			printk(KERN_ERR"swim3: unknown state %d\n", fs->state);
532*1da177e4SLinus Torvalds 			return;
533*1da177e4SLinus Torvalds 		}
534*1da177e4SLinus Torvalds 	}
535*1da177e4SLinus Torvalds }
536*1da177e4SLinus Torvalds 
537*1da177e4SLinus Torvalds static void scan_timeout(unsigned long data)
538*1da177e4SLinus Torvalds {
539*1da177e4SLinus Torvalds 	struct floppy_state *fs = (struct floppy_state *) data;
540*1da177e4SLinus Torvalds 	struct swim3 __iomem *sw = fs->swim3;
541*1da177e4SLinus Torvalds 
542*1da177e4SLinus Torvalds 	fs->timeout_pending = 0;
543*1da177e4SLinus Torvalds 	out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS);
544*1da177e4SLinus Torvalds 	out_8(&sw->select, RELAX);
545*1da177e4SLinus Torvalds 	out_8(&sw->intr_enable, 0);
546*1da177e4SLinus Torvalds 	fs->cur_cyl = -1;
547*1da177e4SLinus Torvalds 	if (fs->retries > 5) {
548*1da177e4SLinus Torvalds 		end_request(fd_req, 0);
549*1da177e4SLinus Torvalds 		fs->state = idle;
550*1da177e4SLinus Torvalds 		start_request(fs);
551*1da177e4SLinus Torvalds 	} else {
552*1da177e4SLinus Torvalds 		fs->state = jogging;
553*1da177e4SLinus Torvalds 		act(fs);
554*1da177e4SLinus Torvalds 	}
555*1da177e4SLinus Torvalds }
556*1da177e4SLinus Torvalds 
557*1da177e4SLinus Torvalds static void seek_timeout(unsigned long data)
558*1da177e4SLinus Torvalds {
559*1da177e4SLinus Torvalds 	struct floppy_state *fs = (struct floppy_state *) data;
560*1da177e4SLinus Torvalds 	struct swim3 __iomem *sw = fs->swim3;
561*1da177e4SLinus Torvalds 
562*1da177e4SLinus Torvalds 	fs->timeout_pending = 0;
563*1da177e4SLinus Torvalds 	out_8(&sw->control_bic, DO_SEEK);
564*1da177e4SLinus Torvalds 	out_8(&sw->select, RELAX);
565*1da177e4SLinus Torvalds 	out_8(&sw->intr_enable, 0);
566*1da177e4SLinus Torvalds 	printk(KERN_ERR "swim3: seek timeout\n");
567*1da177e4SLinus Torvalds 	end_request(fd_req, 0);
568*1da177e4SLinus Torvalds 	fs->state = idle;
569*1da177e4SLinus Torvalds 	start_request(fs);
570*1da177e4SLinus Torvalds }
571*1da177e4SLinus Torvalds 
572*1da177e4SLinus Torvalds static void settle_timeout(unsigned long data)
573*1da177e4SLinus Torvalds {
574*1da177e4SLinus Torvalds 	struct floppy_state *fs = (struct floppy_state *) data;
575*1da177e4SLinus Torvalds 	struct swim3 __iomem *sw = fs->swim3;
576*1da177e4SLinus Torvalds 
577*1da177e4SLinus Torvalds 	fs->timeout_pending = 0;
578*1da177e4SLinus Torvalds 	if (swim3_readbit(fs, SEEK_COMPLETE)) {
579*1da177e4SLinus Torvalds 		out_8(&sw->select, RELAX);
580*1da177e4SLinus Torvalds 		fs->state = locating;
581*1da177e4SLinus Torvalds 		act(fs);
582*1da177e4SLinus Torvalds 		return;
583*1da177e4SLinus Torvalds 	}
584*1da177e4SLinus Torvalds 	out_8(&sw->select, RELAX);
585*1da177e4SLinus Torvalds 	if (fs->settle_time < 2*HZ) {
586*1da177e4SLinus Torvalds 		++fs->settle_time;
587*1da177e4SLinus Torvalds 		set_timeout(fs, 1, settle_timeout);
588*1da177e4SLinus Torvalds 		return;
589*1da177e4SLinus Torvalds 	}
590*1da177e4SLinus Torvalds 	printk(KERN_ERR "swim3: seek settle timeout\n");
591*1da177e4SLinus Torvalds 	end_request(fd_req, 0);
592*1da177e4SLinus Torvalds 	fs->state = idle;
593*1da177e4SLinus Torvalds 	start_request(fs);
594*1da177e4SLinus Torvalds }
595*1da177e4SLinus Torvalds 
596*1da177e4SLinus Torvalds static void xfer_timeout(unsigned long data)
597*1da177e4SLinus Torvalds {
598*1da177e4SLinus Torvalds 	struct floppy_state *fs = (struct floppy_state *) data;
599*1da177e4SLinus Torvalds 	struct swim3 __iomem *sw = fs->swim3;
600*1da177e4SLinus Torvalds 	struct dbdma_regs __iomem *dr = fs->dma;
601*1da177e4SLinus Torvalds 	struct dbdma_cmd *cp = fs->dma_cmd;
602*1da177e4SLinus Torvalds 	unsigned long s;
603*1da177e4SLinus Torvalds 	int n;
604*1da177e4SLinus Torvalds 
605*1da177e4SLinus Torvalds 	fs->timeout_pending = 0;
606*1da177e4SLinus Torvalds 	out_le32(&dr->control, RUN << 16);
607*1da177e4SLinus Torvalds 	/* We must wait a bit for dbdma to stop */
608*1da177e4SLinus Torvalds 	for (n = 0; (in_le32(&dr->status) & ACTIVE) && n < 1000; n++)
609*1da177e4SLinus Torvalds 		udelay(1);
610*1da177e4SLinus Torvalds 	out_8(&sw->intr_enable, 0);
611*1da177e4SLinus Torvalds 	out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION);
612*1da177e4SLinus Torvalds 	out_8(&sw->select, RELAX);
613*1da177e4SLinus Torvalds 	if (rq_data_dir(fd_req) == WRITE)
614*1da177e4SLinus Torvalds 		++cp;
615*1da177e4SLinus Torvalds 	if (ld_le16(&cp->xfer_status) != 0)
616*1da177e4SLinus Torvalds 		s = fs->scount - ((ld_le16(&cp->res_count) + 511) >> 9);
617*1da177e4SLinus Torvalds 	else
618*1da177e4SLinus Torvalds 		s = 0;
619*1da177e4SLinus Torvalds 	fd_req->sector += s;
620*1da177e4SLinus Torvalds 	fd_req->current_nr_sectors -= s;
621*1da177e4SLinus Torvalds 	printk(KERN_ERR "swim3: timeout %sing sector %ld\n",
622*1da177e4SLinus Torvalds 	       (rq_data_dir(fd_req)==WRITE? "writ": "read"), (long)fd_req->sector);
623*1da177e4SLinus Torvalds 	end_request(fd_req, 0);
624*1da177e4SLinus Torvalds 	fs->state = idle;
625*1da177e4SLinus Torvalds 	start_request(fs);
626*1da177e4SLinus Torvalds }
627*1da177e4SLinus Torvalds 
628*1da177e4SLinus Torvalds static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
629*1da177e4SLinus Torvalds {
630*1da177e4SLinus Torvalds 	struct floppy_state *fs = (struct floppy_state *) dev_id;
631*1da177e4SLinus Torvalds 	struct swim3 __iomem *sw = fs->swim3;
632*1da177e4SLinus Torvalds 	int intr, err, n;
633*1da177e4SLinus Torvalds 	int stat, resid;
634*1da177e4SLinus Torvalds 	struct dbdma_regs __iomem *dr;
635*1da177e4SLinus Torvalds 	struct dbdma_cmd *cp;
636*1da177e4SLinus Torvalds 
637*1da177e4SLinus Torvalds 	intr = in_8(&sw->intr);
638*1da177e4SLinus Torvalds 	err = (intr & ERROR_INTR)? in_8(&sw->error): 0;
639*1da177e4SLinus Torvalds 	if ((intr & ERROR_INTR) && fs->state != do_transfer)
640*1da177e4SLinus Torvalds 		printk(KERN_ERR "swim3_interrupt, state=%d, dir=%lx, intr=%x, err=%x\n",
641*1da177e4SLinus Torvalds 		       fs->state, rq_data_dir(fd_req), intr, err);
642*1da177e4SLinus Torvalds 	switch (fs->state) {
643*1da177e4SLinus Torvalds 	case locating:
644*1da177e4SLinus Torvalds 		if (intr & SEEN_SECTOR) {
645*1da177e4SLinus Torvalds 			out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS);
646*1da177e4SLinus Torvalds 			out_8(&sw->select, RELAX);
647*1da177e4SLinus Torvalds 			out_8(&sw->intr_enable, 0);
648*1da177e4SLinus Torvalds 			del_timer(&fs->timeout);
649*1da177e4SLinus Torvalds 			fs->timeout_pending = 0;
650*1da177e4SLinus Torvalds 			if (sw->ctrack == 0xff) {
651*1da177e4SLinus Torvalds 				printk(KERN_ERR "swim3: seen sector but cyl=ff?\n");
652*1da177e4SLinus Torvalds 				fs->cur_cyl = -1;
653*1da177e4SLinus Torvalds 				if (fs->retries > 5) {
654*1da177e4SLinus Torvalds 					end_request(fd_req, 0);
655*1da177e4SLinus Torvalds 					fs->state = idle;
656*1da177e4SLinus Torvalds 					start_request(fs);
657*1da177e4SLinus Torvalds 				} else {
658*1da177e4SLinus Torvalds 					fs->state = jogging;
659*1da177e4SLinus Torvalds 					act(fs);
660*1da177e4SLinus Torvalds 				}
661*1da177e4SLinus Torvalds 				break;
662*1da177e4SLinus Torvalds 			}
663*1da177e4SLinus Torvalds 			fs->cur_cyl = sw->ctrack;
664*1da177e4SLinus Torvalds 			fs->cur_sector = sw->csect;
665*1da177e4SLinus Torvalds 			if (fs->expect_cyl != -1 && fs->expect_cyl != fs->cur_cyl)
666*1da177e4SLinus Torvalds 				printk(KERN_ERR "swim3: expected cyl %d, got %d\n",
667*1da177e4SLinus Torvalds 				       fs->expect_cyl, fs->cur_cyl);
668*1da177e4SLinus Torvalds 			fs->state = do_transfer;
669*1da177e4SLinus Torvalds 			act(fs);
670*1da177e4SLinus Torvalds 		}
671*1da177e4SLinus Torvalds 		break;
672*1da177e4SLinus Torvalds 	case seeking:
673*1da177e4SLinus Torvalds 	case jogging:
674*1da177e4SLinus Torvalds 		if (sw->nseek == 0) {
675*1da177e4SLinus Torvalds 			out_8(&sw->control_bic, DO_SEEK);
676*1da177e4SLinus Torvalds 			out_8(&sw->select, RELAX);
677*1da177e4SLinus Torvalds 			out_8(&sw->intr_enable, 0);
678*1da177e4SLinus Torvalds 			del_timer(&fs->timeout);
679*1da177e4SLinus Torvalds 			fs->timeout_pending = 0;
680*1da177e4SLinus Torvalds 			if (fs->state == seeking)
681*1da177e4SLinus Torvalds 				++fs->retries;
682*1da177e4SLinus Torvalds 			fs->state = settling;
683*1da177e4SLinus Torvalds 			act(fs);
684*1da177e4SLinus Torvalds 		}
685*1da177e4SLinus Torvalds 		break;
686*1da177e4SLinus Torvalds 	case settling:
687*1da177e4SLinus Torvalds 		out_8(&sw->intr_enable, 0);
688*1da177e4SLinus Torvalds 		del_timer(&fs->timeout);
689*1da177e4SLinus Torvalds 		fs->timeout_pending = 0;
690*1da177e4SLinus Torvalds 		act(fs);
691*1da177e4SLinus Torvalds 		break;
692*1da177e4SLinus Torvalds 	case do_transfer:
693*1da177e4SLinus Torvalds 		if ((intr & (ERROR_INTR | TRANSFER_DONE)) == 0)
694*1da177e4SLinus Torvalds 			break;
695*1da177e4SLinus Torvalds 		out_8(&sw->intr_enable, 0);
696*1da177e4SLinus Torvalds 		out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION);
697*1da177e4SLinus Torvalds 		out_8(&sw->select, RELAX);
698*1da177e4SLinus Torvalds 		del_timer(&fs->timeout);
699*1da177e4SLinus Torvalds 		fs->timeout_pending = 0;
700*1da177e4SLinus Torvalds 		dr = fs->dma;
701*1da177e4SLinus Torvalds 		cp = fs->dma_cmd;
702*1da177e4SLinus Torvalds 		if (rq_data_dir(fd_req) == WRITE)
703*1da177e4SLinus Torvalds 			++cp;
704*1da177e4SLinus Torvalds 		/*
705*1da177e4SLinus Torvalds 		 * Check that the main data transfer has finished.
706*1da177e4SLinus Torvalds 		 * On writing, the swim3 sometimes doesn't use
707*1da177e4SLinus Torvalds 		 * up all the bytes of the postamble, so we can still
708*1da177e4SLinus Torvalds 		 * see DMA active here.  That doesn't matter as long
709*1da177e4SLinus Torvalds 		 * as all the sector data has been transferred.
710*1da177e4SLinus Torvalds 		 */
711*1da177e4SLinus Torvalds 		if ((intr & ERROR_INTR) == 0 && cp->xfer_status == 0) {
712*1da177e4SLinus Torvalds 			/* wait a little while for DMA to complete */
713*1da177e4SLinus Torvalds 			for (n = 0; n < 100; ++n) {
714*1da177e4SLinus Torvalds 				if (cp->xfer_status != 0)
715*1da177e4SLinus Torvalds 					break;
716*1da177e4SLinus Torvalds 				udelay(1);
717*1da177e4SLinus Torvalds 				barrier();
718*1da177e4SLinus Torvalds 			}
719*1da177e4SLinus Torvalds 		}
720*1da177e4SLinus Torvalds 		/* turn off DMA */
721*1da177e4SLinus Torvalds 		out_le32(&dr->control, (RUN | PAUSE) << 16);
722*1da177e4SLinus Torvalds 		stat = ld_le16(&cp->xfer_status);
723*1da177e4SLinus Torvalds 		resid = ld_le16(&cp->res_count);
724*1da177e4SLinus Torvalds 		if (intr & ERROR_INTR) {
725*1da177e4SLinus Torvalds 			n = fs->scount - 1 - resid / 512;
726*1da177e4SLinus Torvalds 			if (n > 0) {
727*1da177e4SLinus Torvalds 				fd_req->sector += n;
728*1da177e4SLinus Torvalds 				fd_req->current_nr_sectors -= n;
729*1da177e4SLinus Torvalds 				fd_req->buffer += n * 512;
730*1da177e4SLinus Torvalds 				fs->req_sector += n;
731*1da177e4SLinus Torvalds 			}
732*1da177e4SLinus Torvalds 			if (fs->retries < 5) {
733*1da177e4SLinus Torvalds 				++fs->retries;
734*1da177e4SLinus Torvalds 				act(fs);
735*1da177e4SLinus Torvalds 			} else {
736*1da177e4SLinus Torvalds 				printk("swim3: error %sing block %ld (err=%x)\n",
737*1da177e4SLinus Torvalds 				       rq_data_dir(fd_req) == WRITE? "writ": "read",
738*1da177e4SLinus Torvalds 				       (long)fd_req->sector, err);
739*1da177e4SLinus Torvalds 				end_request(fd_req, 0);
740*1da177e4SLinus Torvalds 				fs->state = idle;
741*1da177e4SLinus Torvalds 			}
742*1da177e4SLinus Torvalds 		} else {
743*1da177e4SLinus Torvalds 			if ((stat & ACTIVE) == 0 || resid != 0) {
744*1da177e4SLinus Torvalds 				/* musta been an error */
745*1da177e4SLinus Torvalds 				printk(KERN_ERR "swim3: fd dma: stat=%x resid=%d\n", stat, resid);
746*1da177e4SLinus Torvalds 				printk(KERN_ERR "  state=%d, dir=%lx, intr=%x, err=%x\n",
747*1da177e4SLinus Torvalds 				       fs->state, rq_data_dir(fd_req), intr, err);
748*1da177e4SLinus Torvalds 				end_request(fd_req, 0);
749*1da177e4SLinus Torvalds 				fs->state = idle;
750*1da177e4SLinus Torvalds 				start_request(fs);
751*1da177e4SLinus Torvalds 				break;
752*1da177e4SLinus Torvalds 			}
753*1da177e4SLinus Torvalds 			fd_req->sector += fs->scount;
754*1da177e4SLinus Torvalds 			fd_req->current_nr_sectors -= fs->scount;
755*1da177e4SLinus Torvalds 			fd_req->buffer += fs->scount * 512;
756*1da177e4SLinus Torvalds 			if (fd_req->current_nr_sectors <= 0) {
757*1da177e4SLinus Torvalds 				end_request(fd_req, 1);
758*1da177e4SLinus Torvalds 				fs->state = idle;
759*1da177e4SLinus Torvalds 			} else {
760*1da177e4SLinus Torvalds 				fs->req_sector += fs->scount;
761*1da177e4SLinus Torvalds 				if (fs->req_sector > fs->secpertrack) {
762*1da177e4SLinus Torvalds 					fs->req_sector -= fs->secpertrack;
763*1da177e4SLinus Torvalds 					if (++fs->head > 1) {
764*1da177e4SLinus Torvalds 						fs->head = 0;
765*1da177e4SLinus Torvalds 						++fs->req_cyl;
766*1da177e4SLinus Torvalds 					}
767*1da177e4SLinus Torvalds 				}
768*1da177e4SLinus Torvalds 				act(fs);
769*1da177e4SLinus Torvalds 			}
770*1da177e4SLinus Torvalds 		}
771*1da177e4SLinus Torvalds 		if (fs->state == idle)
772*1da177e4SLinus Torvalds 			start_request(fs);
773*1da177e4SLinus Torvalds 		break;
774*1da177e4SLinus Torvalds 	default:
775*1da177e4SLinus Torvalds 		printk(KERN_ERR "swim3: don't know what to do in state %d\n", fs->state);
776*1da177e4SLinus Torvalds 	}
777*1da177e4SLinus Torvalds 	return IRQ_HANDLED;
778*1da177e4SLinus Torvalds }
779*1da177e4SLinus Torvalds 
780*1da177e4SLinus Torvalds /*
781*1da177e4SLinus Torvalds static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
782*1da177e4SLinus Torvalds {
783*1da177e4SLinus Torvalds }
784*1da177e4SLinus Torvalds */
785*1da177e4SLinus Torvalds 
786*1da177e4SLinus Torvalds static int grab_drive(struct floppy_state *fs, enum swim_state state,
787*1da177e4SLinus Torvalds 		      int interruptible)
788*1da177e4SLinus Torvalds {
789*1da177e4SLinus Torvalds 	unsigned long flags;
790*1da177e4SLinus Torvalds 
791*1da177e4SLinus Torvalds 	save_flags(flags);
792*1da177e4SLinus Torvalds 	cli();
793*1da177e4SLinus Torvalds 	if (fs->state != idle) {
794*1da177e4SLinus Torvalds 		++fs->wanted;
795*1da177e4SLinus Torvalds 		while (fs->state != available) {
796*1da177e4SLinus Torvalds 			if (interruptible && signal_pending(current)) {
797*1da177e4SLinus Torvalds 				--fs->wanted;
798*1da177e4SLinus Torvalds 				restore_flags(flags);
799*1da177e4SLinus Torvalds 				return -EINTR;
800*1da177e4SLinus Torvalds 			}
801*1da177e4SLinus Torvalds 			interruptible_sleep_on(&fs->wait);
802*1da177e4SLinus Torvalds 		}
803*1da177e4SLinus Torvalds 		--fs->wanted;
804*1da177e4SLinus Torvalds 	}
805*1da177e4SLinus Torvalds 	fs->state = state;
806*1da177e4SLinus Torvalds 	restore_flags(flags);
807*1da177e4SLinus Torvalds 	return 0;
808*1da177e4SLinus Torvalds }
809*1da177e4SLinus Torvalds 
810*1da177e4SLinus Torvalds static void release_drive(struct floppy_state *fs)
811*1da177e4SLinus Torvalds {
812*1da177e4SLinus Torvalds 	unsigned long flags;
813*1da177e4SLinus Torvalds 
814*1da177e4SLinus Torvalds 	save_flags(flags);
815*1da177e4SLinus Torvalds 	cli();
816*1da177e4SLinus Torvalds 	fs->state = idle;
817*1da177e4SLinus Torvalds 	start_request(fs);
818*1da177e4SLinus Torvalds 	restore_flags(flags);
819*1da177e4SLinus Torvalds }
820*1da177e4SLinus Torvalds 
821*1da177e4SLinus Torvalds static int fd_eject(struct floppy_state *fs)
822*1da177e4SLinus Torvalds {
823*1da177e4SLinus Torvalds 	int err, n;
824*1da177e4SLinus Torvalds 
825*1da177e4SLinus Torvalds 	err = grab_drive(fs, ejecting, 1);
826*1da177e4SLinus Torvalds 	if (err)
827*1da177e4SLinus Torvalds 		return err;
828*1da177e4SLinus Torvalds 	swim3_action(fs, EJECT);
829*1da177e4SLinus Torvalds 	for (n = 20; n > 0; --n) {
830*1da177e4SLinus Torvalds 		if (signal_pending(current)) {
831*1da177e4SLinus Torvalds 			err = -EINTR;
832*1da177e4SLinus Torvalds 			break;
833*1da177e4SLinus Torvalds 		}
834*1da177e4SLinus Torvalds 		swim3_select(fs, RELAX);
835*1da177e4SLinus Torvalds 		current->state = TASK_INTERRUPTIBLE;
836*1da177e4SLinus Torvalds 		schedule_timeout(1);
837*1da177e4SLinus Torvalds 		if (swim3_readbit(fs, DISK_IN) == 0)
838*1da177e4SLinus Torvalds 			break;
839*1da177e4SLinus Torvalds 	}
840*1da177e4SLinus Torvalds 	swim3_select(fs, RELAX);
841*1da177e4SLinus Torvalds 	udelay(150);
842*1da177e4SLinus Torvalds 	fs->ejected = 1;
843*1da177e4SLinus Torvalds 	release_drive(fs);
844*1da177e4SLinus Torvalds 	return err;
845*1da177e4SLinus Torvalds }
846*1da177e4SLinus Torvalds 
847*1da177e4SLinus Torvalds static struct floppy_struct floppy_type =
848*1da177e4SLinus Torvalds 	{ 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL };	/*  7 1.44MB 3.5"   */
849*1da177e4SLinus Torvalds 
850*1da177e4SLinus Torvalds static int floppy_ioctl(struct inode *inode, struct file *filp,
851*1da177e4SLinus Torvalds 			unsigned int cmd, unsigned long param)
852*1da177e4SLinus Torvalds {
853*1da177e4SLinus Torvalds 	struct floppy_state *fs = inode->i_bdev->bd_disk->private_data;
854*1da177e4SLinus Torvalds 	int err;
855*1da177e4SLinus Torvalds 
856*1da177e4SLinus Torvalds 	if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN))
857*1da177e4SLinus Torvalds 		return -EPERM;
858*1da177e4SLinus Torvalds 
859*1da177e4SLinus Torvalds 	if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
860*1da177e4SLinus Torvalds 		return -ENXIO;
861*1da177e4SLinus Torvalds 
862*1da177e4SLinus Torvalds 	switch (cmd) {
863*1da177e4SLinus Torvalds 	case FDEJECT:
864*1da177e4SLinus Torvalds 		if (fs->ref_count != 1)
865*1da177e4SLinus Torvalds 			return -EBUSY;
866*1da177e4SLinus Torvalds 		err = fd_eject(fs);
867*1da177e4SLinus Torvalds 		return err;
868*1da177e4SLinus Torvalds 	case FDGETPRM:
869*1da177e4SLinus Torvalds 	        if (copy_to_user((void __user *) param, &floppy_type,
870*1da177e4SLinus Torvalds 				 sizeof(struct floppy_struct)))
871*1da177e4SLinus Torvalds 			return -EFAULT;
872*1da177e4SLinus Torvalds 		return 0;
873*1da177e4SLinus Torvalds 	}
874*1da177e4SLinus Torvalds 	return -ENOTTY;
875*1da177e4SLinus Torvalds }
876*1da177e4SLinus Torvalds 
877*1da177e4SLinus Torvalds static int floppy_open(struct inode *inode, struct file *filp)
878*1da177e4SLinus Torvalds {
879*1da177e4SLinus Torvalds 	struct floppy_state *fs = inode->i_bdev->bd_disk->private_data;
880*1da177e4SLinus Torvalds 	struct swim3 __iomem *sw = fs->swim3;
881*1da177e4SLinus Torvalds 	int n, err = 0;
882*1da177e4SLinus Torvalds 
883*1da177e4SLinus Torvalds 	if (fs->ref_count == 0) {
884*1da177e4SLinus Torvalds 		if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
885*1da177e4SLinus Torvalds 			return -ENXIO;
886*1da177e4SLinus Torvalds 		out_8(&sw->setup, S_IBM_DRIVE | S_FCLK_DIV2);
887*1da177e4SLinus Torvalds 		out_8(&sw->control_bic, 0xff);
888*1da177e4SLinus Torvalds 		out_8(&sw->mode, 0x95);
889*1da177e4SLinus Torvalds 		udelay(10);
890*1da177e4SLinus Torvalds 		out_8(&sw->intr_enable, 0);
891*1da177e4SLinus Torvalds 		out_8(&sw->control_bis, DRIVE_ENABLE | INTR_ENABLE);
892*1da177e4SLinus Torvalds 		swim3_action(fs, MOTOR_ON);
893*1da177e4SLinus Torvalds 		fs->write_prot = -1;
894*1da177e4SLinus Torvalds 		fs->cur_cyl = -1;
895*1da177e4SLinus Torvalds 		for (n = 0; n < 2 * HZ; ++n) {
896*1da177e4SLinus Torvalds 			if (n >= HZ/30 && swim3_readbit(fs, SEEK_COMPLETE))
897*1da177e4SLinus Torvalds 				break;
898*1da177e4SLinus Torvalds 			if (signal_pending(current)) {
899*1da177e4SLinus Torvalds 				err = -EINTR;
900*1da177e4SLinus Torvalds 				break;
901*1da177e4SLinus Torvalds 			}
902*1da177e4SLinus Torvalds 			swim3_select(fs, RELAX);
903*1da177e4SLinus Torvalds 			current->state = TASK_INTERRUPTIBLE;
904*1da177e4SLinus Torvalds 			schedule_timeout(1);
905*1da177e4SLinus Torvalds 		}
906*1da177e4SLinus Torvalds 		if (err == 0 && (swim3_readbit(fs, SEEK_COMPLETE) == 0
907*1da177e4SLinus Torvalds 				 || swim3_readbit(fs, DISK_IN) == 0))
908*1da177e4SLinus Torvalds 			err = -ENXIO;
909*1da177e4SLinus Torvalds 		swim3_action(fs, SETMFM);
910*1da177e4SLinus Torvalds 		swim3_select(fs, RELAX);
911*1da177e4SLinus Torvalds 
912*1da177e4SLinus Torvalds 	} else if (fs->ref_count == -1 || filp->f_flags & O_EXCL)
913*1da177e4SLinus Torvalds 		return -EBUSY;
914*1da177e4SLinus Torvalds 
915*1da177e4SLinus Torvalds 	if (err == 0 && (filp->f_flags & O_NDELAY) == 0
916*1da177e4SLinus Torvalds 	    && (filp->f_mode & 3)) {
917*1da177e4SLinus Torvalds 		check_disk_change(inode->i_bdev);
918*1da177e4SLinus Torvalds 		if (fs->ejected)
919*1da177e4SLinus Torvalds 			err = -ENXIO;
920*1da177e4SLinus Torvalds 	}
921*1da177e4SLinus Torvalds 
922*1da177e4SLinus Torvalds 	if (err == 0 && (filp->f_mode & 2)) {
923*1da177e4SLinus Torvalds 		if (fs->write_prot < 0)
924*1da177e4SLinus Torvalds 			fs->write_prot = swim3_readbit(fs, WRITE_PROT);
925*1da177e4SLinus Torvalds 		if (fs->write_prot)
926*1da177e4SLinus Torvalds 			err = -EROFS;
927*1da177e4SLinus Torvalds 	}
928*1da177e4SLinus Torvalds 
929*1da177e4SLinus Torvalds 	if (err) {
930*1da177e4SLinus Torvalds 		if (fs->ref_count == 0) {
931*1da177e4SLinus Torvalds 			swim3_action(fs, MOTOR_OFF);
932*1da177e4SLinus Torvalds 			out_8(&sw->control_bic, DRIVE_ENABLE | INTR_ENABLE);
933*1da177e4SLinus Torvalds 			swim3_select(fs, RELAX);
934*1da177e4SLinus Torvalds 		}
935*1da177e4SLinus Torvalds 		return err;
936*1da177e4SLinus Torvalds 	}
937*1da177e4SLinus Torvalds 
938*1da177e4SLinus Torvalds 	if (filp->f_flags & O_EXCL)
939*1da177e4SLinus Torvalds 		fs->ref_count = -1;
940*1da177e4SLinus Torvalds 	else
941*1da177e4SLinus Torvalds 		++fs->ref_count;
942*1da177e4SLinus Torvalds 
943*1da177e4SLinus Torvalds 	return 0;
944*1da177e4SLinus Torvalds }
945*1da177e4SLinus Torvalds 
946*1da177e4SLinus Torvalds static int floppy_release(struct inode *inode, struct file *filp)
947*1da177e4SLinus Torvalds {
948*1da177e4SLinus Torvalds 	struct floppy_state *fs = inode->i_bdev->bd_disk->private_data;
949*1da177e4SLinus Torvalds 	struct swim3 __iomem *sw = fs->swim3;
950*1da177e4SLinus Torvalds 	if (fs->ref_count > 0 && --fs->ref_count == 0) {
951*1da177e4SLinus Torvalds 		swim3_action(fs, MOTOR_OFF);
952*1da177e4SLinus Torvalds 		out_8(&sw->control_bic, 0xff);
953*1da177e4SLinus Torvalds 		swim3_select(fs, RELAX);
954*1da177e4SLinus Torvalds 	}
955*1da177e4SLinus Torvalds 	return 0;
956*1da177e4SLinus Torvalds }
957*1da177e4SLinus Torvalds 
958*1da177e4SLinus Torvalds static int floppy_check_change(struct gendisk *disk)
959*1da177e4SLinus Torvalds {
960*1da177e4SLinus Torvalds 	struct floppy_state *fs = disk->private_data;
961*1da177e4SLinus Torvalds 	return fs->ejected;
962*1da177e4SLinus Torvalds }
963*1da177e4SLinus Torvalds 
964*1da177e4SLinus Torvalds static int floppy_revalidate(struct gendisk *disk)
965*1da177e4SLinus Torvalds {
966*1da177e4SLinus Torvalds 	struct floppy_state *fs = disk->private_data;
967*1da177e4SLinus Torvalds 	struct swim3 __iomem *sw;
968*1da177e4SLinus Torvalds 	int ret, n;
969*1da177e4SLinus Torvalds 
970*1da177e4SLinus Torvalds 	if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
971*1da177e4SLinus Torvalds 		return -ENXIO;
972*1da177e4SLinus Torvalds 
973*1da177e4SLinus Torvalds 	sw = fs->swim3;
974*1da177e4SLinus Torvalds 	grab_drive(fs, revalidating, 0);
975*1da177e4SLinus Torvalds 	out_8(&sw->intr_enable, 0);
976*1da177e4SLinus Torvalds 	out_8(&sw->control_bis, DRIVE_ENABLE);
977*1da177e4SLinus Torvalds 	swim3_action(fs, MOTOR_ON);	/* necessary? */
978*1da177e4SLinus Torvalds 	fs->write_prot = -1;
979*1da177e4SLinus Torvalds 	fs->cur_cyl = -1;
980*1da177e4SLinus Torvalds 	mdelay(1);
981*1da177e4SLinus Torvalds 	for (n = HZ; n > 0; --n) {
982*1da177e4SLinus Torvalds 		if (swim3_readbit(fs, SEEK_COMPLETE))
983*1da177e4SLinus Torvalds 			break;
984*1da177e4SLinus Torvalds 		if (signal_pending(current))
985*1da177e4SLinus Torvalds 			break;
986*1da177e4SLinus Torvalds 		swim3_select(fs, RELAX);
987*1da177e4SLinus Torvalds 		current->state = TASK_INTERRUPTIBLE;
988*1da177e4SLinus Torvalds 		schedule_timeout(1);
989*1da177e4SLinus Torvalds 	}
990*1da177e4SLinus Torvalds 	ret = swim3_readbit(fs, SEEK_COMPLETE) == 0
991*1da177e4SLinus Torvalds 		|| swim3_readbit(fs, DISK_IN) == 0;
992*1da177e4SLinus Torvalds 	if (ret)
993*1da177e4SLinus Torvalds 		swim3_action(fs, MOTOR_OFF);
994*1da177e4SLinus Torvalds 	else {
995*1da177e4SLinus Torvalds 		fs->ejected = 0;
996*1da177e4SLinus Torvalds 		swim3_action(fs, SETMFM);
997*1da177e4SLinus Torvalds 	}
998*1da177e4SLinus Torvalds 	swim3_select(fs, RELAX);
999*1da177e4SLinus Torvalds 
1000*1da177e4SLinus Torvalds 	release_drive(fs);
1001*1da177e4SLinus Torvalds 	return ret;
1002*1da177e4SLinus Torvalds }
1003*1da177e4SLinus Torvalds 
1004*1da177e4SLinus Torvalds static struct block_device_operations floppy_fops = {
1005*1da177e4SLinus Torvalds 	.open		= floppy_open,
1006*1da177e4SLinus Torvalds 	.release	= floppy_release,
1007*1da177e4SLinus Torvalds 	.ioctl		= floppy_ioctl,
1008*1da177e4SLinus Torvalds 	.media_changed	= floppy_check_change,
1009*1da177e4SLinus Torvalds 	.revalidate_disk= floppy_revalidate,
1010*1da177e4SLinus Torvalds };
1011*1da177e4SLinus Torvalds 
1012*1da177e4SLinus Torvalds int swim3_init(void)
1013*1da177e4SLinus Torvalds {
1014*1da177e4SLinus Torvalds 	struct device_node *swim;
1015*1da177e4SLinus Torvalds 	int err = -ENOMEM;
1016*1da177e4SLinus Torvalds 	int i;
1017*1da177e4SLinus Torvalds 
1018*1da177e4SLinus Torvalds 	devfs_mk_dir("floppy");
1019*1da177e4SLinus Torvalds 
1020*1da177e4SLinus Torvalds 	swim = find_devices("floppy");
1021*1da177e4SLinus Torvalds 	while (swim && (floppy_count < MAX_FLOPPIES))
1022*1da177e4SLinus Torvalds 	{
1023*1da177e4SLinus Torvalds 		swim3_add_device(swim);
1024*1da177e4SLinus Torvalds 		swim = swim->next;
1025*1da177e4SLinus Torvalds 	}
1026*1da177e4SLinus Torvalds 
1027*1da177e4SLinus Torvalds 	swim = find_devices("swim3");
1028*1da177e4SLinus Torvalds 	while (swim && (floppy_count < MAX_FLOPPIES))
1029*1da177e4SLinus Torvalds 	{
1030*1da177e4SLinus Torvalds 		swim3_add_device(swim);
1031*1da177e4SLinus Torvalds 		swim = swim->next;
1032*1da177e4SLinus Torvalds 	}
1033*1da177e4SLinus Torvalds 
1034*1da177e4SLinus Torvalds 	if (!floppy_count)
1035*1da177e4SLinus Torvalds 		return -ENODEV;
1036*1da177e4SLinus Torvalds 
1037*1da177e4SLinus Torvalds 	for (i = 0; i < floppy_count; i++) {
1038*1da177e4SLinus Torvalds 		disks[i] = alloc_disk(1);
1039*1da177e4SLinus Torvalds 		if (!disks[i])
1040*1da177e4SLinus Torvalds 			goto out;
1041*1da177e4SLinus Torvalds 	}
1042*1da177e4SLinus Torvalds 
1043*1da177e4SLinus Torvalds 	if (register_blkdev(FLOPPY_MAJOR, "fd")) {
1044*1da177e4SLinus Torvalds 		err = -EBUSY;
1045*1da177e4SLinus Torvalds 		goto out;
1046*1da177e4SLinus Torvalds 	}
1047*1da177e4SLinus Torvalds 
1048*1da177e4SLinus Torvalds 	swim3_queue = blk_init_queue(do_fd_request, &swim3_lock);
1049*1da177e4SLinus Torvalds 	if (!swim3_queue) {
1050*1da177e4SLinus Torvalds 		err = -ENOMEM;
1051*1da177e4SLinus Torvalds 		goto out_queue;
1052*1da177e4SLinus Torvalds 	}
1053*1da177e4SLinus Torvalds 
1054*1da177e4SLinus Torvalds 	for (i = 0; i < floppy_count; i++) {
1055*1da177e4SLinus Torvalds 		struct gendisk *disk = disks[i];
1056*1da177e4SLinus Torvalds 		disk->major = FLOPPY_MAJOR;
1057*1da177e4SLinus Torvalds 		disk->first_minor = i;
1058*1da177e4SLinus Torvalds 		disk->fops = &floppy_fops;
1059*1da177e4SLinus Torvalds 		disk->private_data = &floppy_states[i];
1060*1da177e4SLinus Torvalds 		disk->queue = swim3_queue;
1061*1da177e4SLinus Torvalds 		disk->flags |= GENHD_FL_REMOVABLE;
1062*1da177e4SLinus Torvalds 		sprintf(disk->disk_name, "fd%d", i);
1063*1da177e4SLinus Torvalds 		sprintf(disk->devfs_name, "floppy/%d", i);
1064*1da177e4SLinus Torvalds 		set_capacity(disk, 2880);
1065*1da177e4SLinus Torvalds 		add_disk(disk);
1066*1da177e4SLinus Torvalds 	}
1067*1da177e4SLinus Torvalds 	return 0;
1068*1da177e4SLinus Torvalds 
1069*1da177e4SLinus Torvalds out_queue:
1070*1da177e4SLinus Torvalds 	unregister_blkdev(FLOPPY_MAJOR, "fd");
1071*1da177e4SLinus Torvalds out:
1072*1da177e4SLinus Torvalds 	while (i--)
1073*1da177e4SLinus Torvalds 		put_disk(disks[i]);
1074*1da177e4SLinus Torvalds 	/* shouldn't we do something with results of swim_add_device()? */
1075*1da177e4SLinus Torvalds 	return err;
1076*1da177e4SLinus Torvalds }
1077*1da177e4SLinus Torvalds 
1078*1da177e4SLinus Torvalds static int swim3_add_device(struct device_node *swim)
1079*1da177e4SLinus Torvalds {
1080*1da177e4SLinus Torvalds 	struct device_node *mediabay;
1081*1da177e4SLinus Torvalds 	struct floppy_state *fs = &floppy_states[floppy_count];
1082*1da177e4SLinus Torvalds 
1083*1da177e4SLinus Torvalds 	if (swim->n_addrs < 2)
1084*1da177e4SLinus Torvalds 	{
1085*1da177e4SLinus Torvalds 		printk(KERN_INFO "swim3: expecting 2 addrs (n_addrs:%d, n_intrs:%d)\n",
1086*1da177e4SLinus Torvalds 		       swim->n_addrs, swim->n_intrs);
1087*1da177e4SLinus Torvalds 		return -EINVAL;
1088*1da177e4SLinus Torvalds 	}
1089*1da177e4SLinus Torvalds 
1090*1da177e4SLinus Torvalds 	if (swim->n_intrs < 2)
1091*1da177e4SLinus Torvalds 	{
1092*1da177e4SLinus Torvalds 		printk(KERN_INFO "swim3: expecting 2 intrs (n_addrs:%d, n_intrs:%d)\n",
1093*1da177e4SLinus Torvalds 		       swim->n_addrs, swim->n_intrs);
1094*1da177e4SLinus Torvalds 		return -EINVAL;
1095*1da177e4SLinus Torvalds 	}
1096*1da177e4SLinus Torvalds 
1097*1da177e4SLinus Torvalds 	if (!request_OF_resource(swim, 0, NULL)) {
1098*1da177e4SLinus Torvalds 		printk(KERN_INFO "swim3: can't request IO resource !\n");
1099*1da177e4SLinus Torvalds 		return -EINVAL;
1100*1da177e4SLinus Torvalds 	}
1101*1da177e4SLinus Torvalds 
1102*1da177e4SLinus Torvalds 	mediabay = (strcasecmp(swim->parent->type, "media-bay") == 0) ? swim->parent : NULL;
1103*1da177e4SLinus Torvalds 	if (mediabay == NULL)
1104*1da177e4SLinus Torvalds 		pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 1);
1105*1da177e4SLinus Torvalds 
1106*1da177e4SLinus Torvalds 	memset(fs, 0, sizeof(*fs));
1107*1da177e4SLinus Torvalds 	fs->state = idle;
1108*1da177e4SLinus Torvalds 	fs->swim3 = (struct swim3 __iomem *)
1109*1da177e4SLinus Torvalds 		ioremap(swim->addrs[0].address, 0x200);
1110*1da177e4SLinus Torvalds 	fs->dma = (struct dbdma_regs __iomem *)
1111*1da177e4SLinus Torvalds 		ioremap(swim->addrs[1].address, 0x200);
1112*1da177e4SLinus Torvalds 	fs->swim3_intr = swim->intrs[0].line;
1113*1da177e4SLinus Torvalds 	fs->dma_intr = swim->intrs[1].line;
1114*1da177e4SLinus Torvalds 	fs->cur_cyl = -1;
1115*1da177e4SLinus Torvalds 	fs->cur_sector = -1;
1116*1da177e4SLinus Torvalds 	fs->secpercyl = 36;
1117*1da177e4SLinus Torvalds 	fs->secpertrack = 18;
1118*1da177e4SLinus Torvalds 	fs->total_secs = 2880;
1119*1da177e4SLinus Torvalds 	fs->media_bay = mediabay;
1120*1da177e4SLinus Torvalds 	init_waitqueue_head(&fs->wait);
1121*1da177e4SLinus Torvalds 
1122*1da177e4SLinus Torvalds 	fs->dma_cmd = (struct dbdma_cmd *) DBDMA_ALIGN(fs->dbdma_cmd_space);
1123*1da177e4SLinus Torvalds 	memset(fs->dma_cmd, 0, 2 * sizeof(struct dbdma_cmd));
1124*1da177e4SLinus Torvalds 	st_le16(&fs->dma_cmd[1].command, DBDMA_STOP);
1125*1da177e4SLinus Torvalds 
1126*1da177e4SLinus Torvalds 	if (request_irq(fs->swim3_intr, swim3_interrupt, 0, "SWIM3", fs)) {
1127*1da177e4SLinus Torvalds 		printk(KERN_ERR "Couldn't get irq %d for SWIM3\n", fs->swim3_intr);
1128*1da177e4SLinus Torvalds 		pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 0);
1129*1da177e4SLinus Torvalds 		return -EBUSY;
1130*1da177e4SLinus Torvalds 	}
1131*1da177e4SLinus Torvalds /*
1132*1da177e4SLinus Torvalds 	if (request_irq(fs->dma_intr, fd_dma_interrupt, 0, "SWIM3-dma", fs)) {
1133*1da177e4SLinus Torvalds 		printk(KERN_ERR "Couldn't get irq %d for SWIM3 DMA",
1134*1da177e4SLinus Torvalds 		       fs->dma_intr);
1135*1da177e4SLinus Torvalds 		pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 0);
1136*1da177e4SLinus Torvalds 		return -EBUSY;
1137*1da177e4SLinus Torvalds 	}
1138*1da177e4SLinus Torvalds */
1139*1da177e4SLinus Torvalds 
1140*1da177e4SLinus Torvalds 	init_timer(&fs->timeout);
1141*1da177e4SLinus Torvalds 
1142*1da177e4SLinus Torvalds 	printk(KERN_INFO "fd%d: SWIM3 floppy controller %s\n", floppy_count,
1143*1da177e4SLinus Torvalds 		mediabay ? "in media bay" : "");
1144*1da177e4SLinus Torvalds 
1145*1da177e4SLinus Torvalds 	floppy_count++;
1146*1da177e4SLinus Torvalds 
1147*1da177e4SLinus Torvalds 	return 0;
1148*1da177e4SLinus Torvalds }
1149*1da177e4SLinus Torvalds 
1150*1da177e4SLinus Torvalds module_init(swim3_init)
1151*1da177e4SLinus Torvalds 
1152*1da177e4SLinus Torvalds MODULE_LICENSE("GPL");
1153*1da177e4SLinus Torvalds MODULE_AUTHOR("Paul Mackerras");
1154*1da177e4SLinus Torvalds MODULE_ALIAS_BLOCKDEV_MAJOR(FLOPPY_MAJOR);
1155