1/*
2 * linux/arch/arm/drivers/block/mfmhd.c
3 *
4 * Copyright (C) 1995, 1996 Russell King, Dave Alan Gilbert (gilbertd@cs.man.ac.uk)
5 *
6 * MFM hard drive code [experimental]
7 */
8
9/*
10 * Change list:
11 *
12 *  3/2/96:DAG: Started a change list :-)
13 *              Set the hardsect_size pointers up since we are running 256 byte
14 *                sectors
15 *              Added DMA code, put it into the rw_intr
16 *              Moved RCAL out of generic interrupt code - don't want to do it
17 *                while DMA'ing - its now in individual handlers.
18 *              Took interrupt handlers off task queue lists and called
19 *                directly - not sure of implications.
20 *
21 * 18/2/96:DAG: Well its reading OK I think, well enough for image file code
22 *              to find the image file; but now I've discovered that I actually
23 *              have to put some code in for image files.
24 *
25 *              Added stuff for image files; seems to work, but I've not
26 *              got a multisegment image file (I don't think!).
27 *              Put in a hack (yep a real hack) for multiple cylinder reads.
28 *              Not convinced its working.
29 *
30 *  5/4/96:DAG: Added asm/hardware.h and use IOC_ macros
31 *              Rewrote dma code in mfm.S (again!) - now takes a word at a time
32 *              from main RAM for speed; still doesn't feel speedy!
33 *
34 * 20/4/96:DAG: After rewriting mfm.S a heck of a lot of times and speeding
35 *              things up, I've finally figured out why its so damn slow.
36 *              Linux is only reading a block at a time, and so you never
37 *              get more than 1K per disc revoloution ~=60K/second.
38 *
39 * 27/4/96:DAG: On Russell's advice I change ll_rw_blk.c to ask it to
40 *              join adjacent blocks together. Everything falls flat on its
41 *              face.
42 *              Four hours of debugging later; I hadn't realised that
43 *              ll_rw_blk would be so generous as to join blocks whose
44 *              results aren't going into consecutive buffers.
45 *
46 *              OK; severe rehacking of mfm_rw_interrupt; now end_request's
47 *              as soon as its DMA'd each request.  Odd thing is that
48 *              we are sometimes getting interrupts where we are not transferring
49 *              any data; why? Is that what happens when you miss? I doubt
50 *              it; are we too fast? No - its just at command ends. Got 240K/s
51 *              better than before, but RiscOS hits 480K/s
52 *
53 * 25/6/96:RMK: Fixed init code to allow the MFM podule to work.  Increased the
54 *              number of errors for my Miniscribe drive (8425).
55 *
56 * 30/6/96:DAG: Russell suggested that a check drive 0 might turn the LEDs off
57 *              - so in request_done just before it clears Busy it sends a
58 *              check drive 0 - and the LEDs go off!!!!
59 *
60 *              Added test for mainboard controller. - Removes need for separate
61 *              define.
62 *
63 * 13/7/96:DAG: Changed hardware sectore size to 512 in attempt to make
64 *              IM drivers work.
65 * 21/7/96:DAG: Took out old image file stuff (accessing it now produces an IO
66 *              error.)
67 *
68 * 17/8/96:DAG: Ran through indent -kr -i8; evil - all my nice 2 character indents
69 *              gone :-( Hand modified afterwards.
70 *		Took out last remains of the older image map system.
71 *
72 * 22/9/96:DAG:	Changed mfm.S so it will carry on DMA'ing til; BSY is dropped
73 *		Changed mfm_rw_intr so that it doesn't follow the error
74 *		code until BSY is dropped. Nope - still broke. Problem
75 *		may revolve around when it reads the results for the error
76 *		number?
77 *
78 *16/11/96:DAG:	Modified for 2.0.18; request_irq changed
79 *
80 *17/12/96:RMK: Various cleanups, reorganisation, and the changes for new IO system.
81 *		Improved probe for onboard MFM chip - it was hanging on my A5k.
82 *		Added autodetect CHS code such that we don't rely on the presence
83 *		of an ADFS boot block.  Added ioport resource manager calls so
84 *		that we don't clash with already-running hardware (eg. RiscPC Ether
85 *		card slots if someone tries this)!
86 *
87 * 17/1/97:RMK:	Upgraded to 2.1 kernels.
88 *
89 *  4/3/98:RMK:	Changed major number to 21.
90 *
91 * 27/6/98:RMK:	Changed asm/delay.h to linux/delay.h for mdelay().
92 */
93
94/*
95 * Possible enhancements:
96 *  Multi-thread the code so that it is possible that while one drive
97 *  is seeking, the other one can be reading data/seeking as well.
98 *  This would be a performance boost with dual drive systems.
99 */
100
101#include <linux/module.h>
102#include <linux/config.h>
103#include <linux/sched.h>
104#include <linux/fs.h>
105#include <linux/interrupt.h>
106#include <linux/kernel.h>
107#include <linux/timer.h>
108#include <linux/tqueue.h>
109#include <linux/mm.h>
110#include <linux/errno.h>
111#include <linux/genhd.h>
112#include <linux/major.h>
113#include <linux/ioport.h>
114#include <linux/delay.h>
115
116#define MAJOR_NR	MFM_ACORN_MAJOR
117#include <linux/blk.h>
118#include <linux/blkpg.h>
119
120#include <asm/system.h>
121#include <asm/io.h>
122#include <asm/irq.h>
123#include <asm/uaccess.h>
124#include <asm/dma.h>
125#include <asm/hardware.h>
126#include <asm/ecard.h>
127#include <asm/hardware/ioc.h>
128
129/*
130 * This sort of stuff should be in a header file shared with ide.c, hd.c, xd.c etc
131 */
132#ifndef HDIO_GETGEO
133#define HDIO_GETGEO 0x301
134struct hd_geometry {
135	unsigned char heads;
136	unsigned char sectors;
137	unsigned short cylinders;
138	unsigned long start;
139};
140#endif
141
142
143/*
144 * Configuration section
145 *
146 * This is the maximum number of drives that we accept
147 */
148#define MFM_MAXDRIVES 2
149/*
150 * Linux I/O address of onboard MFM controller or 0 to disable this
151 */
152#define ONBOARD_MFM_ADDRESS ((0x002d0000 >> 2) | 0x80000000)
153/*
154 * Uncomment this to enable debugging in the MFM driver...
155 */
156#ifndef DEBUG
157/*#define DEBUG */
158#endif
159/*
160 * List of card types that we recognise
161 */
162static const card_ids mfm_cids[] = {
163	{ MANU_ACORN, PROD_ACORN_MFM },
164	{ 0xffff, 0xffff }
165};
166/*
167 * End of configuration
168 */
169
170
171/*
172 * This structure contains all information to do with a particular physical
173 * device.
174 */
175struct mfm_info {
176	unsigned char sectors;
177	unsigned char heads;
178	unsigned short cylinders;
179	unsigned short lowcurrent;
180	unsigned short precomp;
181#define NO_TRACK -1
182#define NEED_1_RECAL -2
183#define NEED_2_RECAL -3
184		 int cylinder;
185	unsigned int access_count;
186	unsigned int busy;
187	struct {
188		char recal;
189		char report;
190		char abort;
191	} errors;
192} mfm_info[MFM_MAXDRIVES];
193
194#define MFM_DRV_INFO mfm_info[raw_cmd.dev]
195
196static struct hd_struct mfm[MFM_MAXDRIVES << 6];
197static int mfm_sizes[MFM_MAXDRIVES << 6];
198static int mfm_blocksizes[MFM_MAXDRIVES << 6];
199static int mfm_sectsizes[MFM_MAXDRIVES << 6];
200static DECLARE_WAIT_QUEUE_HEAD(mfm_wait_open);
201
202/* Stuff from the assembly routines */
203extern unsigned int hdc63463_baseaddress;	/* Controller base address */
204extern unsigned int hdc63463_irqpolladdress;	/* Address to read to test for int */
205extern unsigned int hdc63463_irqpollmask;	/* Mask for irq register */
206extern unsigned int hdc63463_dataptr;	/* Pointer to kernel data space to DMA */
207extern int hdc63463_dataleft;	/* Number of bytes left to transfer */
208
209
210
211
212static int lastspecifieddrive;
213static unsigned Busy;
214
215static unsigned int PartFragRead;	/* The number of sectors which have been read
216					   during a partial read split over two
217					   cylinders.  If 0 it means a partial
218					   read did not occur. */
219
220static unsigned int PartFragRead_RestartBlock;	/* Where to restart on a split access */
221static unsigned int PartFragRead_SectorsLeft;	/* Where to restart on a split access */
222
223static int Sectors256LeftInCurrent;	/* i.e. 256 byte sectors left in current */
224static int SectorsLeftInRequest;	/* i.e. blocks left in the thing mfm_request was called for */
225static int Copy_Sector;		/* The 256 byte sector we are currently at - fragments need to know
226				   where to take over */
227static char *Copy_buffer;
228
229
230static void mfm_seek(void);
231static void mfm_rerequest(void);
232static void mfm_request(void);
233static int mfm_reread_partitions(kdev_t dev);
234static void mfm_specify (void);
235static void issue_request(int dev, unsigned int block, unsigned int nsect,
236			  struct request *req);
237
238static unsigned int mfm_addr;		/* Controller address */
239static unsigned int mfm_IRQPollLoc;	/* Address to read for IRQ information */
240static unsigned int mfm_irqenable;	/* Podule IRQ enable location */
241static unsigned char mfm_irq;		/* Interrupt number */
242static int mfm_drives = 0;		/* drives available */
243static int mfm_status = 0;		/* interrupt status */
244static int *errors;
245
246static struct rawcmd {
247	unsigned int dev;
248	unsigned int cylinder;
249	unsigned int head;
250	unsigned int sector;
251	unsigned int cmdtype;
252	unsigned int cmdcode;
253	unsigned char cmddata[16];
254	unsigned int cmdlen;
255} raw_cmd;
256
257static unsigned char result[16];
258
259static struct cont {
260	void (*interrupt) (void);	/* interrupt handler */
261	void (*error) (void);	/* error handler */
262	void (*redo) (void);	/* redo handler */
263	void (*done) (int st);	/* done handler */
264} *cont = NULL;
265
266
267int number_mfm_drives = 1;
268
269/* ------------------------------------------------------------------------------------------ */
270/*
271 * From the HD63463 data sheet from Hitachi Ltd.
272 */
273
274#define MFM_COMMAND (mfm_addr + 0)
275#define MFM_DATAOUT (mfm_addr + 1)
276#define MFM_STATUS  (mfm_addr + 8)
277#define MFM_DATAIN  (mfm_addr + 9)
278
279#define CMD_ABT		0xF0	/* Abort */
280#define CMD_SPC		0xE8	/* Specify */
281#define CMD_TST		0xE0	/* Test */
282#define CMD_RCLB	0xC8	/* Recalibrate */
283#define CMD_SEK		0xC0	/* Seek */
284#define CMD_WFS		0xAB	/* Write Format Skew */
285#define CMD_WFM		0xA3	/* Write Format */
286#define CMD_MTB		0x90	/* Memory to buffer */
287#define CMD_CMPD	0x88	/* Compare data */
288#define CMD_WD		0x87	/* Write data */
289#define CMD_RED		0x70	/* Read erroneous data */
290#define CMD_RIS		0x68	/* Read ID skew */
291#define CMD_FID		0x61	/* Find ID */
292#define CMD_RID		0x60	/* Read ID */
293#define CMD_BTM		0x50	/* Buffer to memory */
294#define CMD_CKD		0x48	/* Check data */
295#define CMD_RD		0x40	/* Read data */
296#define CMD_OPBW	0x38	/* Open buffer write */
297#define CMD_OPBR	0x30	/* Open buffer read */
298#define CMD_CKV		0x28	/* Check drive */
299#define CMD_CKE		0x20	/* Check ECC */
300#define CMD_POD		0x18	/* Polling disable */
301#define CMD_POL		0x10	/* Polling enable */
302#define CMD_RCAL	0x08	/* Recall */
303
304#define STAT_BSY	0x8000	/* Busy */
305#define STAT_CPR	0x4000	/* Command Parameter Rejection */
306#define STAT_CED	0x2000	/* Command end */
307#define STAT_SED	0x1000	/* Seek end */
308#define STAT_DER	0x0800	/* Drive error */
309#define STAT_ABN	0x0400	/* Abnormal end */
310#define STAT_POL	0x0200	/* Polling */
311
312/* ------------------------------------------------------------------------------------------ */
313#ifdef DEBUG
314static void console_printf(const char *fmt,...)
315{
316	static char buffer[2048];	/* Arbitary! */
317	extern void console_print(const char *);
318	unsigned long flags;
319	va_list ap;
320
321	save_flags_cli(flags);
322
323	va_start(ap, fmt);
324	vsprintf(buffer, fmt, ap);
325	console_print(buffer);
326	va_end(fmt);
327
328	restore_flags(flags);
329};	/* console_printf */
330
331#define DBG(x...) console_printf(x)
332#else
333#define DBG(x...)
334#endif
335
336static void print_status(void)
337{
338	char *error;
339	static char *errors[] = {
340         "no error",
341	 "command aborted",
342	 "invalid command",
343	 "parameter error",
344	 "not initialised",
345	 "rejected TEST",
346	 "no useld",
347	 "write fault",
348	 "not ready",
349	 "no scp",
350	 "in seek",
351	 "invalid NCA",
352	 "invalid step rate",
353	 "seek error",
354	 "over run",
355	 "invalid PHA",
356	 "data field EEC error",
357	 "data field CRC error",
358	 "error corrected",
359	 "data field fatal error",
360	 "no data am",
361	 "not hit",
362	 "ID field CRC error",
363	 "time over",
364	 "no ID am",
365	 "not writable"
366	};
367	if (result[1] < 0x65)
368		error = errors[result[1] >> 2];
369	else
370		error = "unknown";
371	printk("(");
372	if (mfm_status & STAT_BSY) printk("BSY ");
373	if (mfm_status & STAT_CPR) printk("CPR ");
374	if (mfm_status & STAT_CED) printk("CED ");
375	if (mfm_status & STAT_SED) printk("SED ");
376	if (mfm_status & STAT_DER) printk("DER ");
377	if (mfm_status & STAT_ABN) printk("ABN ");
378	if (mfm_status & STAT_POL) printk("POL ");
379	printk(") SSB = %X (%s)\n", result[1], error);
380
381}
382
383/* ------------------------------------------------------------------------------------- */
384
385static void issue_command(int command, unsigned char *cmdb, int len)
386{
387	int status;
388#ifdef DEBUG
389	int i;
390	console_printf("issue_command: %02X: ", command);
391	for (i = 0; i < len; i++)
392		console_printf("%02X ", cmdb[i]);
393	console_printf("\n");
394#endif
395
396	do {
397		status = inw(MFM_STATUS);
398	} while (status & (STAT_BSY | STAT_POL));
399	DBG("issue_command: status after pol/bsy loop: %02X:\n ", status >> 8);
400
401	if (status & (STAT_CPR | STAT_CED | STAT_SED | STAT_DER | STAT_ABN)) {
402		outw(CMD_RCAL, MFM_COMMAND);
403		while (inw(MFM_STATUS) & STAT_BSY);
404	}
405	status = inw(MFM_STATUS);
406	DBG("issue_command: status before parameter issue: %02X:\n ", status >> 8);
407
408	while (len > 0) {
409		outw(cmdb[1] | (cmdb[0] << 8), MFM_DATAOUT);
410		len -= 2;
411		cmdb += 2;
412	}
413	status = inw(MFM_STATUS);
414	DBG("issue_command: status before command issue: %02X:\n ", status >> 8);
415
416	outw(command, MFM_COMMAND);
417	status = inw(MFM_STATUS);
418	DBG("issue_command: status immediatly after command issue: %02X:\n ", status >> 8);
419}
420
421static void wait_for_completion(void)
422{
423	while ((mfm_status = inw(MFM_STATUS)) & STAT_BSY);
424}
425
426static void wait_for_command_end(void)
427{
428	int i;
429
430	while (!((mfm_status = inw(MFM_STATUS)) & STAT_CED));
431
432	for (i = 0; i < 16;) {
433		int in;
434		in = inw(MFM_DATAIN);
435		result[i++] = in >> 8;
436		result[i++] = in;
437	}
438	outw (CMD_RCAL, MFM_COMMAND);
439}
440
441/* ------------------------------------------------------------------------------------- */
442
443static void mfm_rw_intr(void)
444{
445	int old_status;		/* Holds status on entry, we read to see if the command just finished */
446#ifdef DEBUG
447	console_printf("mfm_rw_intr...dataleft=%d\n", hdc63463_dataleft);
448	print_status();
449#endif
450
451  /* Now don't handle the error until BSY drops */
452	if ((mfm_status & (STAT_DER | STAT_ABN)) && ((mfm_status&STAT_BSY)==0)) {
453		/* Something has gone wrong - let's try that again */
454		outw(CMD_RCAL, MFM_COMMAND);	/* Clear interrupt condition */
455		if (cont) {
456			DBG("mfm_rw_intr: DER/ABN err\n");
457			cont->error();
458			cont->redo();
459		};
460		return;
461	};
462
463	/* OK so what ever happend its not an error, now I reckon we are left between
464	   a choice of command end or some data which is ready to be collected */
465	/* I think we have to transfer data while the interrupt line is on and its
466	   not any other type of interrupt */
467	if (CURRENT->cmd == WRITE) {
468		extern void hdc63463_writedma(void);
469		if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) {
470			printk("mfm_rw_intr: Apparent DMA write request when no more to DMA\n");
471			if (cont) {
472				cont->error();
473				cont->redo();
474			};
475			return;
476		};
477		hdc63463_writedma();
478	} else {
479		extern void hdc63463_readdma(void);
480		if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) {
481			printk("mfm_rw_intr: Apparent DMA read request when no more to DMA\n");
482			if (cont) {
483				cont->error();
484				cont->redo();
485			};
486			return;
487		};
488		DBG("Going to try read dma..............status=0x%x, buffer=%p\n", mfm_status, hdc63463_dataptr);
489		hdc63463_readdma();
490	};			/* Read */
491
492	if (hdc63463_dataptr != ((unsigned int) Copy_buffer + 256)) {
493		/* If we didn't actually manage to get any data on this interrupt - but why? We got the interrupt */
494		/* Ah - well looking at the status its just when we get command end; so no problem */
495		/*console_printf("mfm: dataptr mismatch. dataptr=0x%08x Copy_buffer+256=0x%08p\n",
496		   hdc63463_dataptr,Copy_buffer+256);
497		   print_status(); */
498	} else {
499		Sectors256LeftInCurrent--;
500		Copy_buffer += 256;
501		Copy_Sector++;
502
503		/* We have come to the end of this request */
504		if (!Sectors256LeftInCurrent) {
505			DBG("mfm: end_request for CURRENT=0x%p CURRENT(sector=%d current_nr_sectors=%d nr_sectors=%d)\n",
506				       CURRENT, CURRENT->sector, CURRENT->current_nr_sectors, CURRENT->nr_sectors);
507
508			CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
509			CURRENT->sector += CURRENT->current_nr_sectors;
510			SectorsLeftInRequest -= CURRENT->current_nr_sectors;
511
512			end_request(1);
513			if (SectorsLeftInRequest) {
514				hdc63463_dataptr = (unsigned int) CURRENT->buffer;
515				Copy_buffer = CURRENT->buffer;
516				Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2;
517				errors = &(CURRENT->errors);
518				/* These should match the present calculations of the next logical sector
519				   on the device
520				   Copy_Sector=CURRENT->sector*2; */
521
522				if (Copy_Sector != CURRENT->sector * 2)
523#ifdef DEBUG
524					/*console_printf*/printk("mfm: Copy_Sector mismatch. Copy_Sector=%d CURRENT->sector*2=%d\n",
525					Copy_Sector, CURRENT->sector * 2);
526#else
527					printk("mfm: Copy_Sector mismatch! Eek!\n");
528#endif
529			};	/* CURRENT */
530		};	/* Sectors256LeftInCurrent */
531	};
532
533	old_status = mfm_status;
534	mfm_status = inw(MFM_STATUS);
535	if (mfm_status & (STAT_DER | STAT_ABN)) {
536		/* Something has gone wrong - let's try that again */
537		if (cont) {
538			DBG("mfm_rw_intr: DER/ABN error\n");
539			cont->error();
540			cont->redo();
541		};
542		return;
543	};
544
545	/* If this code wasn't entered due to command_end but there is
546	   now a command end we must read the command results out. If it was
547	   entered like this then mfm_interrupt_handler would have done the
548	   job. */
549	if ((!((old_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) &&
550	    ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) {
551		int len = 0;
552		while (len < 16) {
553			int in;
554			in = inw(MFM_DATAIN);
555			result[len++] = in >> 8;
556			result[len++] = in;
557		};
558	};			/* Result read */
559
560	/*console_printf ("mfm_rw_intr nearexit [%02X]\n", __raw_readb(mfm_IRQPollLoc)); */
561
562	/* If end of command move on */
563	if (mfm_status & (STAT_CED)) {
564		outw(CMD_RCAL, MFM_COMMAND);	/* Clear interrupt condition */
565		/* End of command - trigger the next command */
566		if (cont) {
567			cont->done(1);
568		}
569		DBG("mfm_rw_intr: returned from cont->done\n");
570	} else {
571		/* Its going to generate another interrupt */
572		SET_INTR(mfm_rw_intr);
573	};
574}
575
576static void mfm_setup_rw(void)
577{
578	DBG("setting up for rw...\n");
579
580	SET_INTR(mfm_rw_intr);
581	issue_command(raw_cmd.cmdcode, raw_cmd.cmddata, raw_cmd.cmdlen);
582}
583
584static void mfm_recal_intr(void)
585{
586#ifdef DEBUG
587	console_printf("recal intr - status = ");
588	print_status();
589#endif
590	outw(CMD_RCAL, MFM_COMMAND);	/* Clear interrupt condition */
591	if (mfm_status & (STAT_DER | STAT_ABN)) {
592		printk("recal failed\n");
593		MFM_DRV_INFO.cylinder = NEED_2_RECAL;
594		if (cont) {
595			cont->error();
596			cont->redo();
597		}
598		return;
599	}
600	/* Thats seek end - we are finished */
601	if (mfm_status & STAT_SED) {
602		issue_command(CMD_POD, NULL, 0);
603		MFM_DRV_INFO.cylinder = 0;
604		mfm_seek();
605		return;
606	}
607	/* Command end without seek end (see data sheet p.20) for parallel seek
608	   - we have to send a POL command to wait for the seek */
609	if (mfm_status & STAT_CED) {
610		SET_INTR(mfm_recal_intr);
611		issue_command(CMD_POL, NULL, 0);
612		return;
613	}
614	printk("recal: unknown status\n");
615}
616
617static void mfm_seek_intr(void)
618{
619#ifdef DEBUG
620	console_printf("seek intr - status = ");
621	print_status();
622#endif
623	outw(CMD_RCAL, MFM_COMMAND);	/* Clear interrupt condition */
624	if (mfm_status & (STAT_DER | STAT_ABN)) {
625		printk("seek failed\n");
626		MFM_DRV_INFO.cylinder = NEED_2_RECAL;
627		if (cont) {
628			cont->error();
629			cont->redo();
630		}
631		return;
632	}
633	if (mfm_status & STAT_SED) {
634		issue_command(CMD_POD, NULL, 0);
635		MFM_DRV_INFO.cylinder = raw_cmd.cylinder;
636		mfm_seek();
637		return;
638	}
639	if (mfm_status & STAT_CED) {
640		SET_INTR(mfm_seek_intr);
641		issue_command(CMD_POL, NULL, 0);
642		return;
643	}
644	printk("seek: unknown status\n");
645}
646
647/* IDEA2 seems to work better - its what RiscOS sets my
648 * disc to - on its SECOND call to specify!
649 */
650#define IDEA2
651#ifndef IDEA2
652#define SPEC_SL 0x16
653#define SPEC_SH 0xa9		/* Step pulse high=21, Record Length=001 (256 bytes) */
654#else
655#define SPEC_SL 0x00		/* OM2 - SL - step pulse low */
656#define SPEC_SH 0x21		/* Step pulse high=4, Record Length=001 (256 bytes) */
657#endif
658
659static void mfm_setupspecify (int drive, unsigned char *cmdb)
660{
661	cmdb[0]  = 0x1f;		/* OM0 - !SECT,!MOD,!DIF,PADP,ECD,CRCP,CRCI,ACOR */
662	cmdb[1]  = 0xc3;		/* OM1 - DTM,BRST,!CEDM,!SEDM,!DERM,0,AMEX,PSK */
663	cmdb[2]  = SPEC_SL;		/* OM2 - SL - step pulse low */
664	cmdb[3]  = (number_mfm_drives == 1) ? 0x02 : 0x06;	/* 1 or 2 drives */
665	cmdb[4]  = 0xfc | ((mfm_info[drive].cylinders - 1) >> 8);/* RW time over/high part of number of cylinders */
666	cmdb[5]  = mfm_info[drive].cylinders - 1;		/* low part of number of cylinders */
667	cmdb[6]  = mfm_info[drive].heads - 1;			/* Number of heads */
668	cmdb[7]  = mfm_info[drive].sectors - 1;			/* Number of sectors */
669	cmdb[8]  = SPEC_SH;
670	cmdb[9]  = 0x0a;		/* gap length 1 */
671	cmdb[10] = 0x0d;		/* gap length 2 */
672	cmdb[11] = 0x0c;		/* gap length 3 */
673	cmdb[12] = (mfm_info[drive].precomp - 1) >> 8;	/* pre comp cylinder */
674	cmdb[13] = mfm_info[drive].precomp - 1;
675	cmdb[14] = (mfm_info[drive].lowcurrent - 1) >> 8;	/* Low current cylinder */
676	cmdb[15] = mfm_info[drive].lowcurrent - 1;
677}
678
679static void mfm_specify (void)
680{
681	unsigned char cmdb[16];
682
683	DBG("specify...dev=%d lastspecified=%d\n", raw_cmd.dev, lastspecifieddrive);
684	mfm_setupspecify (raw_cmd.dev, cmdb);
685
686	issue_command (CMD_SPC, cmdb, 16);
687	/* Ensure that we will do another specify if we move to the other drive */
688	lastspecifieddrive = raw_cmd.dev;
689	wait_for_completion();
690}
691
692static void mfm_seek(void)
693{
694	unsigned char cmdb[4];
695
696	DBG("seeking...\n");
697	if (MFM_DRV_INFO.cylinder < 0) {
698		SET_INTR(mfm_recal_intr);
699		DBG("mfm_seek: about to call specify\n");
700		mfm_specify ();	/* DAG added this */
701
702		cmdb[0] = raw_cmd.dev + 1;
703		cmdb[1] = 0;
704
705		issue_command(CMD_RCLB, cmdb, 2);
706		return;
707	}
708	if (MFM_DRV_INFO.cylinder != raw_cmd.cylinder) {
709		cmdb[0] = raw_cmd.dev + 1;
710		cmdb[1] = 0;	/* raw_cmd.head; DAG: My data sheet says this should be 0 */
711		cmdb[2] = raw_cmd.cylinder >> 8;
712		cmdb[3] = raw_cmd.cylinder;
713
714		SET_INTR(mfm_seek_intr);
715		issue_command(CMD_SEK, cmdb, 4);
716	} else
717		mfm_setup_rw();
718}
719
720static void mfm_initialise(void)
721{
722	DBG("init...\n");
723	mfm_seek();
724}
725
726static void request_done(int uptodate)
727{
728	DBG("mfm:request_done\n");
729	if (uptodate) {
730		unsigned char block[2] = {0, 0};
731
732		/* Apparently worked - let's check bytes left to DMA */
733		if (hdc63463_dataleft != (PartFragRead_SectorsLeft * 256)) {
734			printk("mfm: request_done - dataleft=%d - should be %d - Eek!\n", hdc63463_dataleft, PartFragRead_SectorsLeft * 256);
735			end_request(0);
736			Busy = 0;
737		};
738		/* Potentially this means that we've done; but we might be doing
739		   a partial access, (over two cylinders) or we may have a number
740		   of fragments in an image file.  First let's deal with partial accesss
741		 */
742		if (PartFragRead) {
743			/* Yep - a partial access */
744
745			/* and issue the remainder */
746			issue_request(MINOR(CURRENT->rq_dev), PartFragRead_RestartBlock, PartFragRead_SectorsLeft, CURRENT);
747			return;
748		}
749
750		/* ah well - perhaps there is another fragment to go */
751
752		/* Increment pointers/counts to start of next fragment */
753		if (SectorsLeftInRequest > 0) printk("mfm: SectorsLeftInRequest>0 - Eek! Shouldn't happen!\n");
754
755		/* No - its the end of the line */
756		/* end_request's should have happened at the end of sector DMAs */
757		/* Turns Drive LEDs off - may slow it down? */
758		if (QUEUE_EMPTY)
759			issue_command(CMD_CKV, block, 2);
760
761		Busy = 0;
762		DBG("request_done: About to mfm_request\n");
763		/* Next one please */
764		mfm_request();	/* Moved from mfm_rw_intr */
765		DBG("request_done: returned from mfm_request\n");
766	} else {
767		printk("mfm:request_done: update=0\n");
768		end_request(0);
769		Busy = 0;
770	}
771}
772
773static void error_handler(void)
774{
775	printk("error detected... status = ");
776	print_status();
777	(*errors)++;
778	if (*errors > MFM_DRV_INFO.errors.abort)
779		cont->done(0);
780	if (*errors > MFM_DRV_INFO.errors.recal)
781		MFM_DRV_INFO.cylinder = NEED_2_RECAL;
782}
783
784static void rw_interrupt(void)
785{
786	printk("rw_interrupt\n");
787}
788
789static struct cont rw_cont =
790{
791	rw_interrupt,
792	error_handler,
793	mfm_rerequest,
794	request_done
795};
796
797/*
798 * Actually gets round to issuing the request - note everything at this
799 * point is in 256 byte sectors not Linux 512 byte blocks
800 */
801static void issue_request(int dev, unsigned int block, unsigned int nsect,
802			  struct request *req)
803{
804	int track, start_head, start_sector;
805	int sectors_to_next_cyl;
806
807	dev >>= 6;
808
809	track = block / mfm_info[dev].sectors;
810	start_sector = block % mfm_info[dev].sectors;
811	start_head = track % mfm_info[dev].heads;
812
813	/* First get the number of whole tracks which are free before the next
814	   track */
815	sectors_to_next_cyl = (mfm_info[dev].heads - (start_head + 1)) * mfm_info[dev].sectors;
816	/* Then add in the number of sectors left on this track */
817	sectors_to_next_cyl += (mfm_info[dev].sectors - start_sector);
818
819	DBG("issue_request: mfm_info[dev].sectors=%d track=%d\n", mfm_info[dev].sectors, track);
820
821	raw_cmd.dev = dev;
822	raw_cmd.sector = start_sector;
823	raw_cmd.head = start_head;
824	raw_cmd.cylinder = track / mfm_info[dev].heads;
825	raw_cmd.cmdtype = CURRENT->cmd;
826	raw_cmd.cmdcode = CURRENT->cmd == WRITE ? CMD_WD : CMD_RD;
827	raw_cmd.cmddata[0] = dev + 1;	/* DAG: +1 to get US */
828	raw_cmd.cmddata[1] = raw_cmd.head;
829	raw_cmd.cmddata[2] = raw_cmd.cylinder >> 8;
830	raw_cmd.cmddata[3] = raw_cmd.cylinder;
831	raw_cmd.cmddata[4] = raw_cmd.head;
832	raw_cmd.cmddata[5] = raw_cmd.sector;
833
834	/* Was == and worked - how the heck??? */
835	if (lastspecifieddrive != raw_cmd.dev)
836		mfm_specify ();
837
838	if (nsect <= sectors_to_next_cyl) {
839		raw_cmd.cmddata[6] = nsect >> 8;
840		raw_cmd.cmddata[7] = nsect;
841		PartFragRead = 0;	/* All in one */
842		PartFragRead_SectorsLeft = 0;	/* Must set this - used in DMA calcs */
843	} else {
844		raw_cmd.cmddata[6] = sectors_to_next_cyl >> 8;
845		raw_cmd.cmddata[7] = sectors_to_next_cyl;
846		PartFragRead = sectors_to_next_cyl;	/* only do this many this time */
847		PartFragRead_RestartBlock = block + sectors_to_next_cyl;	/* Where to restart from */
848		PartFragRead_SectorsLeft = nsect - sectors_to_next_cyl;
849	}
850	raw_cmd.cmdlen = 8;
851
852	/* Setup DMA pointers */
853	hdc63463_dataptr = (unsigned int) Copy_buffer;
854	hdc63463_dataleft = nsect * 256;	/* Better way? */
855
856	DBG("mfm%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx (%p)\n",
857	     raw_cmd.dev + 'a', (CURRENT->cmd == READ) ? "read" : "writ",
858		       raw_cmd.cylinder,
859		       raw_cmd.head,
860	    raw_cmd.sector, nsect, (unsigned long) Copy_buffer, CURRENT);
861
862	cont = &rw_cont;
863	errors = &(CURRENT->errors);
864	mfm_initialise();
865}				/* issue_request */
866
867/*
868 * Called when an error has just happened - need to trick mfm_request
869 * into thinking we weren't busy
870 *
871 * Turn off ints - mfm_request expects them this way
872 */
873static void mfm_rerequest(void)
874{
875	DBG("mfm_rerequest\n");
876	cli();
877	Busy = 0;
878	mfm_request();
879}
880
881static void mfm_request(void)
882{
883	DBG("mfm_request CURRENT=%p Busy=%d\n", CURRENT, Busy);
884
885	if (QUEUE_EMPTY) {
886		DBG("mfm_request: Exited due to NULL Current 1\n");
887		return;
888	}
889
890	if (CURRENT->rq_status == RQ_INACTIVE) {
891		/* Hmm - seems to be happening a lot on 1.3.45 */
892		/*console_printf("mfm_request: Exited due to INACTIVE Current\n"); */
893		return;
894	}
895
896	/* If we are still processing then return; we will get called again */
897	if (Busy) {
898		/* Again seems to be common in 1.3.45 */
899		/*DBG*/printk("mfm_request: Exiting due to busy\n");
900		return;
901	}
902	Busy = 1;
903
904	while (1) {
905		unsigned int dev, block, nsect;
906
907		DBG("mfm_request: loop start\n");
908		sti();
909
910		DBG("mfm_request: before INIT_REQUEST\n");
911
912		if (QUEUE_EMPTY) {
913			printk("mfm_request: Exiting due to !CURRENT (pre)\n");
914			CLEAR_INTR;
915			Busy = 0;
916			return;
917		};
918
919		INIT_REQUEST;
920
921		DBG("mfm_request:                 before arg extraction\n");
922
923		dev = MINOR(CURRENT->rq_dev);
924		block = CURRENT->sector;
925		nsect = CURRENT->nr_sectors;
926#ifdef DEBUG
927		/*if ((dev>>6)==1) */ console_printf("mfm_request:                                raw vals: dev=%d (block=512 bytes) block=%d nblocks=%d\n", dev, block, nsect);
928#endif
929		if (dev >= (mfm_drives << 6) ||
930		    block >= mfm[dev].nr_sects || ((block+nsect) > mfm[dev].nr_sects)) {
931			if (dev >= (mfm_drives << 6))
932				printk("mfm: bad minor number: device=%s\n", kdevname(CURRENT->rq_dev));
933			else
934				printk("mfm%c: bad access: block=%d, count=%d, nr_sects=%ld\n", (dev >> 6)+'a',
935				       block, nsect, mfm[dev].nr_sects);
936			printk("mfm: continue 1\n");
937			end_request(0);
938			Busy = 0;
939			continue;
940		}
941
942		block += mfm[dev].start_sect;
943
944		/* DAG: Linux doesn't cope with this - even though it has an array telling
945		   it the hardware block size - silly */
946		block <<= 1;	/* Now in 256 byte sectors */
947		nsect <<= 1;	/* Ditto */
948
949		SectorsLeftInRequest = nsect >> 1;
950		Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2;
951		Copy_buffer = CURRENT->buffer;
952		Copy_Sector = CURRENT->sector << 1;
953
954		DBG("mfm_request: block after offset=%d\n", block);
955
956		if (CURRENT->cmd != READ && CURRENT->cmd != WRITE) {
957			printk("unknown mfm-command %d\n", CURRENT->cmd);
958			end_request(0);
959			Busy = 0;
960			printk("mfm: continue 4\n");
961			continue;
962		}
963		issue_request(dev, block, nsect, CURRENT);
964
965		break;
966	}
967	DBG("mfm_request: Dropping out bottom\n");
968}
969
970static void do_mfm_request(request_queue_t *q)
971{
972	DBG("do_mfm_request: about to mfm_request\n");
973	mfm_request();
974}
975
976static void mfm_interrupt_handler(int unused, void *dev_id, struct pt_regs *regs)
977{
978	void (*handler) (void) = DEVICE_INTR;
979
980	CLEAR_INTR;
981
982	DBG("mfm_interrupt_handler (handler=0x%p)\n", handler);
983
984	mfm_status = inw(MFM_STATUS);
985
986	/* If CPR (Command Parameter Reject) and not busy it means that the command
987	   has some return message to give us */
988	if ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR) {
989		int len = 0;
990		while (len < 16) {
991			int in;
992			in = inw(MFM_DATAIN);
993			result[len++] = in >> 8;
994			result[len++] = in;
995		}
996	}
997	if (handler) {
998		handler();
999		return;
1000	}
1001	outw (CMD_RCAL, MFM_COMMAND);	/* Clear interrupt condition */
1002	printk ("mfm: unexpected interrupt - status = ");
1003	print_status ();
1004	while (1);
1005}
1006
1007
1008
1009
1010
1011/*
1012 * Tell the user about the drive if we decided it exists.
1013 */
1014static void mfm_geometry (int drive)
1015{
1016	if (mfm_info[drive].cylinders)
1017		printk ("mfm%c: %dMB CHS=%d/%d/%d LCC=%d RECOMP=%d\n", 'a' + drive,
1018			mfm_info[drive].cylinders * mfm_info[drive].heads * mfm_info[drive].sectors / 4096,
1019			mfm_info[drive].cylinders, mfm_info[drive].heads, mfm_info[drive].sectors,
1020			mfm_info[drive].lowcurrent, mfm_info[drive].precomp);
1021}
1022
1023#ifdef CONFIG_BLK_DEV_MFM_AUTODETECT
1024/*
1025 * Attempt to detect a drive and find its geometry.  The drive has already been
1026 * specified...
1027 *
1028 * We first recalibrate the disk, then try to probe sectors, heads and then
1029 * cylinders.  NOTE! the cylinder probe may break drives.  The xd disk driver
1030 * does something along these lines, so I assume that most drives are up to
1031 * this mistreatment...
1032 */
1033static int mfm_detectdrive (int drive)
1034{
1035	unsigned int mingeo[3], maxgeo[3];
1036	unsigned int attribute, need_recal = 1;
1037	unsigned char cmdb[8];
1038
1039	memset (mingeo, 0, sizeof (mingeo));
1040	maxgeo[0] = mfm_info[drive].sectors;
1041	maxgeo[1] = mfm_info[drive].heads;
1042	maxgeo[2] = mfm_info[drive].cylinders;
1043
1044	cmdb[0] = drive + 1;
1045	cmdb[6] = 0;
1046	cmdb[7] = 1;
1047	for (attribute = 0; attribute < 3; attribute++) {
1048		while (mingeo[attribute] != maxgeo[attribute]) {
1049			unsigned int variable;
1050
1051			variable = (maxgeo[attribute] + mingeo[attribute]) >> 1;
1052			cmdb[1] = cmdb[2] = cmdb[3] = cmdb[4] = cmdb[5] = 0;
1053
1054			if (need_recal) {
1055				int tries = 5;
1056
1057				do {
1058					issue_command (CMD_RCLB, cmdb, 2);
1059					wait_for_completion ();
1060					wait_for_command_end ();
1061					if  (result[1] == 0x20)
1062						break;
1063				} while (result[1] && --tries);
1064				if (result[1]) {
1065					outw (CMD_RCAL, MFM_COMMAND);
1066					return 0;
1067				}
1068				need_recal = 0;
1069			}
1070
1071			switch (attribute) {
1072			case 0:
1073				cmdb[5] = variable;
1074				issue_command (CMD_CMPD, cmdb, 8);
1075				break;
1076			case 1:
1077				cmdb[1] = variable;
1078				cmdb[4] = variable;
1079				issue_command (CMD_CMPD, cmdb, 8);
1080				break;
1081			case 2:
1082				cmdb[2] = variable >> 8;
1083				cmdb[3] = variable;
1084				issue_command (CMD_SEK, cmdb, 4);
1085				break;
1086			}
1087			wait_for_completion ();
1088			wait_for_command_end ();
1089
1090			switch (result[1]) {
1091			case 0x00:
1092			case 0x50:
1093				mingeo[attribute] = variable + 1;
1094				break;
1095
1096			case 0x20:
1097				outw (CMD_RCAL, MFM_COMMAND);
1098				return 0;
1099
1100			case 0x24:
1101				need_recal = 1;
1102			default:
1103				maxgeo[attribute] = variable;
1104				break;
1105			}
1106		}
1107	}
1108	mfm_info[drive].cylinders  = mingeo[2];
1109	mfm_info[drive].lowcurrent = mingeo[2];
1110	mfm_info[drive].precomp    = mingeo[2] / 2;
1111	mfm_info[drive].heads 	   = mingeo[1];
1112	mfm_info[drive].sectors	   = mingeo[0];
1113	outw (CMD_RCAL, MFM_COMMAND);
1114	return 1;
1115}
1116#endif
1117
1118/*
1119 * Initialise all drive information for this controller.
1120 */
1121static int mfm_initdrives(void)
1122{
1123	int drive;
1124
1125	if (number_mfm_drives > MFM_MAXDRIVES) {
1126		number_mfm_drives = MFM_MAXDRIVES;
1127		printk("No. of ADFS MFM drives is greater than MFM_MAXDRIVES - you can't have that many!\n");
1128	}
1129
1130	for (drive = 0; drive < number_mfm_drives; drive++) {
1131		mfm_info[drive].lowcurrent = 1;
1132		mfm_info[drive].precomp    = 1;
1133		mfm_info[drive].cylinder   = -1;
1134		mfm_info[drive].errors.recal  = 0;
1135		mfm_info[drive].errors.report = 0;
1136		mfm_info[drive].errors.abort  = 4;
1137
1138#ifdef CONFIG_BLK_DEV_MFM_AUTODETECT
1139		mfm_info[drive].cylinders  = 1024;
1140		mfm_info[drive].heads	   = 8;
1141		mfm_info[drive].sectors	   = 64;
1142		{
1143			unsigned char cmdb[16];
1144
1145			mfm_setupspecify (drive, cmdb);
1146			cmdb[1] &= ~0x81;
1147			issue_command (CMD_SPC, cmdb, 16);
1148			wait_for_completion ();
1149			if (!mfm_detectdrive (drive)) {
1150				mfm_info[drive].cylinders = 0;
1151				mfm_info[drive].heads     = 0;
1152				mfm_info[drive].sectors   = 0;
1153			}
1154			cmdb[0] = cmdb[1] = 0;
1155			issue_command (CMD_CKV, cmdb, 2);
1156		}
1157#else
1158		mfm_info[drive].cylinders  = 1;	/* its going to have to figure it out from the partition info */
1159		mfm_info[drive].heads      = 4;
1160		mfm_info[drive].sectors    = 32;
1161#endif
1162	}
1163	return number_mfm_drives;
1164}
1165
1166
1167
1168/*
1169 * The 'front' end of the mfm driver follows...
1170 */
1171
1172static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg)
1173{
1174	struct hd_geometry *geo = (struct hd_geometry *) arg;
1175	kdev_t dev;
1176	int device, major, minor, err;
1177
1178	if (!inode || !(dev = inode->i_rdev))
1179		return -EINVAL;
1180
1181	major = MAJOR(dev);
1182	minor = MINOR(dev);
1183
1184	device = DEVICE_NR(MINOR(inode->i_rdev)), err;
1185	if (device >= mfm_drives)
1186		return -EINVAL;
1187
1188	switch (cmd) {
1189	case HDIO_GETGEO:
1190		if (!arg)
1191			return -EINVAL;
1192		if (put_user (mfm_info[device].heads, &geo->heads))
1193			return -EFAULT;
1194		if (put_user (mfm_info[device].sectors, &geo->sectors))
1195			return -EFAULT;
1196		if (put_user (mfm_info[device].cylinders, &geo->cylinders))
1197			return -EFAULT;
1198		if (put_user (mfm[minor].start_sect, &geo->start))
1199			return -EFAULT;
1200		return 0;
1201
1202	case BLKFRASET:
1203		if (!capable(CAP_SYS_ADMIN))
1204			return -EACCES;
1205		max_readahead[major][minor] = arg;
1206		return 0;
1207
1208	case BLKFRAGET:
1209		return put_user(max_readahead[major][minor], (long *) arg);
1210
1211	case BLKSECTGET:
1212		return put_user(max_sectors[major][minor], (long *) arg);
1213
1214	case BLKRRPART:
1215		if (!capable(CAP_SYS_ADMIN))
1216			return -EACCES;
1217		return mfm_reread_partitions(dev);
1218
1219	case BLKGETSIZE:
1220	case BLKGETSIZE64:
1221	case BLKFLSBUF:
1222	case BLKROSET:
1223	case BLKROGET:
1224	case BLKRASET:
1225	case BLKRAGET:
1226	case BLKPG:
1227		return blk_ioctl(dev, cmd, arg);
1228
1229	default:
1230		return -EINVAL;
1231	}
1232}
1233
1234static int mfm_open(struct inode *inode, struct file *file)
1235{
1236	int dev = DEVICE_NR(MINOR(inode->i_rdev));
1237
1238	if (dev >= mfm_drives)
1239		return -ENODEV;
1240
1241	while (mfm_info[dev].busy)
1242		sleep_on (&mfm_wait_open);
1243
1244	mfm_info[dev].access_count++;
1245	return 0;
1246}
1247
1248/*
1249 * Releasing a block device means we sync() it, so that it can safely
1250 * be forgotten about...
1251 */
1252static int mfm_release(struct inode *inode, struct file *file)
1253{
1254	mfm_info[DEVICE_NR(MINOR(inode->i_rdev))].access_count--;
1255	return 0;
1256}
1257
1258/*
1259 * This is to handle various kernel command line parameters
1260 * specific to this driver.
1261 */
1262void mfm_setup(char *str, int *ints)
1263{
1264	return;
1265}
1266
1267/*
1268 * Set the CHS from the ADFS boot block if it is present.  This is not ideal
1269 * since if there are any non-ADFS partitions on the disk, this won't work!
1270 * Hence, I want to get rid of this...
1271 */
1272void xd_set_geometry(kdev_t dev, unsigned char secsptrack, unsigned char heads,
1273		     unsigned long discsize, unsigned int secsize)
1274{
1275	int drive = MINOR(dev) >> 6;
1276
1277	if (mfm_info[drive].cylinders == 1) {
1278		mfm_info[drive].sectors = secsptrack;
1279		mfm_info[drive].heads = heads;
1280		mfm_info[drive].cylinders = discsize / (secsptrack * heads * secsize);
1281
1282		if ((heads < 1) || (mfm_info[drive].cylinders > 1024)) {
1283			printk("mfm%c: Insane disc shape! Setting to 512/4/32\n",'a' + (dev >> 6));
1284
1285			/* These values are fairly arbitary, but are there so that if your
1286			 * lucky you can pick apart your disc to find out what is going on -
1287			 * I reckon these figures won't hurt MOST drives
1288			 */
1289			mfm_info[drive].sectors = 32;
1290			mfm_info[drive].heads = 4;
1291			mfm_info[drive].cylinders = 512;
1292		}
1293		if (raw_cmd.dev == drive)
1294			mfm_specify ();
1295		mfm_geometry (drive);
1296		mfm[drive << 6].start_sect = 0;
1297		mfm[drive << 6].nr_sects = mfm_info[drive].cylinders * mfm_info[drive].heads * mfm_info[drive].sectors / 2;
1298	}
1299}
1300
1301static struct gendisk mfm_gendisk = {
1302	major:		MAJOR_NR,
1303	major_name:	"mfm",
1304	minor_shift:	6,
1305	max_p:		1 << 6,
1306	part:		mfm,
1307	sizes:		mfm_sizes,
1308	real_devices:	(void *)mfm_info,
1309};
1310
1311static struct block_device_operations mfm_fops =
1312{
1313	owner:		THIS_MODULE,
1314	open:		mfm_open,
1315	release:	mfm_release,
1316	ioctl:		mfm_ioctl,
1317};
1318
1319static void mfm_geninit (void)
1320{
1321	int i;
1322
1323	for (i = 0; i < (MFM_MAXDRIVES << 6); i++) {
1324		/* Can't increase this - if you do all hell breaks loose */
1325		mfm_blocksizes[i] = 1024;
1326		mfm_sectsizes[i] = 512;
1327	}
1328	blksize_size[MAJOR_NR] = mfm_blocksizes;
1329	hardsect_size[MAJOR_NR] = mfm_sectsizes;
1330
1331	mfm_drives = mfm_initdrives();
1332
1333	printk("mfm: detected %d hard drive%s\n", mfm_drives,
1334				mfm_drives == 1 ? "" : "s");
1335	mfm_gendisk.nr_real = mfm_drives;
1336
1337	if (request_irq(mfm_irq, mfm_interrupt_handler, SA_INTERRUPT, "MFM harddisk", NULL))
1338		printk("mfm: unable to get IRQ%d\n", mfm_irq);
1339
1340	if (mfm_irqenable)
1341		outw(0x80, mfm_irqenable);	/* Required to enable IRQs from MFM podule */
1342
1343	for (i = 0; i < mfm_drives; i++) {
1344		mfm_geometry (i);
1345		register_disk(&mfm_gendisk, MKDEV(MAJOR_NR,i<<6), 1<<6,
1346				&mfm_fops,
1347				mfm_info[i].cylinders * mfm_info[i].heads *
1348				mfm_info[i].sectors / 2);
1349	}
1350}
1351
1352static struct expansion_card *ecs;
1353
1354/*
1355 * See if there is a controller at the address presently at mfm_addr
1356 *
1357 * We check to see if the controller is busy - if it is, we abort it first,
1358 * and check that the chip is no longer busy after at least 180 clock cycles.
1359 * We then issue a command and check that the BSY or CPR bits are set.
1360 */
1361static int mfm_probecontroller (unsigned int mfm_addr)
1362{
1363	if (inw (MFM_STATUS) & STAT_BSY) {
1364		outw (CMD_ABT, MFM_COMMAND);
1365		udelay (50);
1366		if (inw (MFM_STATUS) & STAT_BSY)
1367			return 0;
1368	}
1369
1370	if (inw (MFM_STATUS) & STAT_CED)
1371		outw (CMD_RCAL, MFM_COMMAND);
1372
1373	outw (CMD_SEK, MFM_COMMAND);
1374
1375	if (inw (MFM_STATUS) & (STAT_BSY | STAT_CPR)) {
1376		unsigned int count = 2000;
1377		while (inw (MFM_STATUS) & STAT_BSY) {
1378			udelay (500);
1379			if (!--count)
1380				return 0;
1381		}
1382
1383		outw (CMD_RCAL, MFM_COMMAND);
1384	}
1385	return 1;
1386}
1387
1388/*
1389 * Look for a MFM controller - first check the motherboard, then the podules
1390 * The podules have an extra interrupt enable that needs to be played with
1391 *
1392 * The HDC is accessed at MEDIUM IOC speeds.
1393 */
1394int mfm_init (void)
1395{
1396	unsigned char irqmask;
1397
1398	if (mfm_probecontroller(ONBOARD_MFM_ADDRESS)) {
1399		mfm_addr	= ONBOARD_MFM_ADDRESS;
1400		mfm_IRQPollLoc	= IOC_IRQSTATB;
1401		mfm_irqenable	= 0;
1402		mfm_irq		= IRQ_HARDDISK;
1403		irqmask		= 0x08;			/* IL3 pin */
1404	} else {
1405		ecs = ecard_find(0, mfm_cids);
1406		if (!ecs) {
1407			mfm_addr = 0;
1408			return -1;
1409		}
1410
1411		mfm_addr	= ecard_address(ecs, ECARD_IOC, ECARD_MEDIUM) + 0x800;
1412		mfm_IRQPollLoc	= ioaddr(mfm_addr + 0x400);
1413		mfm_irqenable	= mfm_IRQPollLoc;
1414		mfm_irq		= ecs->irq;
1415		irqmask		= 0x08;
1416
1417		ecard_claim(ecs);
1418	}
1419
1420	printk("mfm: found at address %08X, interrupt %d\n", mfm_addr, mfm_irq);
1421	if (!request_region (mfm_addr, 10, "mfm")) {
1422		ecard_release(ecs);
1423		return -1;
1424	}
1425
1426	if (register_blkdev(MAJOR_NR, "mfm", &mfm_fops)) {
1427		printk("mfm_init: unable to get major number %d\n", MAJOR_NR);
1428		ecard_release(ecs);
1429		release_region(mfm_addr, 10);
1430		return -1;
1431	}
1432
1433	/* Stuff for the assembler routines to get to */
1434	hdc63463_baseaddress	= ioaddr(mfm_addr);
1435	hdc63463_irqpolladdress	= mfm_IRQPollLoc;
1436	hdc63463_irqpollmask	= irqmask;
1437
1438	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
1439	read_ahead[MAJOR_NR] = 8;	/* 8 sector (4kB?) read ahread */
1440
1441	add_gendisk(&mfm_gendisk);
1442
1443	Busy = 0;
1444	lastspecifieddrive = -1;
1445
1446	mfm_geninit();
1447	return 0;
1448}
1449
1450/*
1451 * This routine is called to flush all partitions and partition tables
1452 * for a changed MFM disk, and then re-read the new partition table.
1453 * If we are revalidating due to an ioctl, we have USAGE == 1.
1454 */
1455static int mfm_reread_partitions(kdev_t dev)
1456{
1457	unsigned int start, i, maxp, target = DEVICE_NR(MINOR(dev));
1458	unsigned long flags;
1459
1460	save_flags_cli(flags);
1461	if (mfm_info[target].busy || mfm_info[target].access_count > 1) {
1462		restore_flags (flags);
1463		return -EBUSY;
1464	}
1465	mfm_info[target].busy = 1;
1466	restore_flags (flags);
1467
1468	maxp = mfm_gendisk.max_p;
1469	start = target << mfm_gendisk.minor_shift;
1470
1471	for (i = maxp - 1; i >= 0; i--) {
1472		int minor = start + i;
1473		invalidate_device (MKDEV(MAJOR_NR, minor), 1);
1474		mfm_gendisk.part[minor].start_sect = 0;
1475		mfm_gendisk.part[minor].nr_sects = 0;
1476	}
1477
1478	/* Divide by 2, since sectors are 2 times smaller than usual ;-) */
1479
1480	grok_partitions(&mfm_gendisk, target, 1<<6, mfm_info[target].heads *
1481		    mfm_info[target].cylinders * mfm_info[target].sectors / 2);
1482
1483	mfm_info[target].busy = 0;
1484	wake_up (&mfm_wait_open);
1485	return 0;
1486}
1487
1488#ifdef MODULE
1489
1490EXPORT_NO_SYMBOLS;
1491MODULE_LICENSE("GPL");
1492
1493int init_module(void)
1494{
1495	return mfm_init();
1496}
1497
1498void cleanup_module(void)
1499{
1500	if (ecs && mfm_irqenable)
1501		outw (0, mfm_irqenable);	/* Required to enable IRQs from MFM podule */
1502	free_irq(mfm_irq, NULL);
1503	unregister_blkdev(MAJOR_NR, "mfm");
1504	del_gendisk(&mfm_gendisk);
1505	if (ecs)
1506		ecard_release(ecs);
1507	if (mfm_addr)
1508		release_region(mfm_addr, 10);
1509}
1510#endif
1511