]> nv-tegra.nvidia Code Review - linux-2.6.git/blob - drivers/acorn/block/mfmhd.c
[PATCH] ARM: switch fd1772.c from sleep_on to wait_event
[linux-2.6.git] / drivers / acorn / block / mfmhd.c
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/mm.h>
109 #include <linux/errno.h>
110 #include <linux/genhd.h>
111 #include <linux/major.h>
112 #include <linux/ioport.h>
113 #include <linux/delay.h>
114 #include <linux/blkpg.h>
115
116 #include <asm/system.h>
117 #include <asm/io.h>
118 #include <asm/irq.h>
119 #include <asm/uaccess.h>
120 #include <asm/dma.h>
121 #include <asm/hardware.h>
122 #include <asm/ecard.h>
123 #include <asm/hardware/ioc.h>
124
125 static void (*do_mfm)(void) = NULL;
126 static struct request_queue *mfm_queue;
127 static DEFINE_SPINLOCK(mfm_lock);
128
129 #define MAJOR_NR        MFM_ACORN_MAJOR
130 #define QUEUE (mfm_queue)
131 #define CURRENT elv_next_request(mfm_queue)
132 /*
133  * This sort of stuff should be in a header file shared with ide.c, hd.c, xd.c etc
134  */
135 #ifndef HDIO_GETGEO
136 #define HDIO_GETGEO 0x301
137 struct hd_geometry {
138         unsigned char heads;
139         unsigned char sectors;
140         unsigned short cylinders;
141         unsigned long start;
142 };
143 #endif
144
145
146 /*
147  * Configuration section
148  *
149  * This is the maximum number of drives that we accept
150  */
151 #define MFM_MAXDRIVES 2
152 /*
153  * Linux I/O address of onboard MFM controller or 0 to disable this
154  */
155 #define ONBOARD_MFM_ADDRESS ((0x002d0000 >> 2) | 0x80000000)
156 /*
157  * Uncomment this to enable debugging in the MFM driver...
158  */
159 #ifndef DEBUG
160 /*#define DEBUG */
161 #endif
162 /*
163  * End of configuration
164  */
165
166  
167 /*
168  * This structure contains all information to do with a particular physical
169  * device.
170  */
171 struct mfm_info {
172         unsigned char sectors;
173         unsigned char heads;
174         unsigned short cylinders;
175         unsigned short lowcurrent;
176         unsigned short precomp;
177 #define NO_TRACK -1
178 #define NEED_1_RECAL -2
179 #define NEED_2_RECAL -3
180                  int cylinder;
181         struct {
182                 char recal;
183                 char report;
184                 char abort;
185         } errors;
186 } mfm_info[MFM_MAXDRIVES];
187
188 #define MFM_DRV_INFO mfm_info[raw_cmd.dev]
189
190 /* Stuff from the assembly routines */
191 extern unsigned int hdc63463_baseaddress;       /* Controller base address */
192 extern unsigned int hdc63463_irqpolladdress;    /* Address to read to test for int */
193 extern unsigned int hdc63463_irqpollmask;       /* Mask for irq register */
194 extern unsigned int hdc63463_dataptr;   /* Pointer to kernel data space to DMA */
195 extern int hdc63463_dataleft;   /* Number of bytes left to transfer */
196
197
198
199
200 static int lastspecifieddrive;
201 static unsigned Busy;
202
203 static unsigned int PartFragRead;       /* The number of sectors which have been read
204                                            during a partial read split over two
205                                            cylinders.  If 0 it means a partial
206                                            read did not occur. */
207
208 static unsigned int PartFragRead_RestartBlock;  /* Where to restart on a split access */
209 static unsigned int PartFragRead_SectorsLeft;   /* Where to restart on a split access */
210
211 static int Sectors256LeftInCurrent;     /* i.e. 256 byte sectors left in current */
212 static int SectorsLeftInRequest;        /* i.e. blocks left in the thing mfm_request was called for */
213 static int Copy_Sector;         /* The 256 byte sector we are currently at - fragments need to know 
214                                    where to take over */
215 static char *Copy_buffer;
216
217
218 static void mfm_seek(void);
219 static void mfm_rerequest(void);
220 static void mfm_request(void);
221 static void mfm_specify (void);
222 static void issue_request(unsigned int block, unsigned int nsect,
223                           struct request *req);
224
225 static unsigned int mfm_addr;           /* Controller address */
226 static unsigned int mfm_IRQPollLoc;     /* Address to read for IRQ information */
227 static unsigned int mfm_irqenable;      /* Podule IRQ enable location */
228 static unsigned char mfm_irq;           /* Interrupt number */
229 static int mfm_drives = 0;              /* drives available */
230 static int mfm_status = 0;              /* interrupt status */
231 static int *errors;
232
233 static struct rawcmd {
234         unsigned int dev;
235         unsigned int cylinder;
236         unsigned int head;
237         unsigned int sector;
238         unsigned int cmdtype;
239         unsigned int cmdcode;
240         unsigned char cmddata[16];
241         unsigned int cmdlen;
242 } raw_cmd;
243
244 static unsigned char result[16];
245
246 static struct cont {
247         void (*interrupt) (void);       /* interrupt handler */
248         void (*error) (void);   /* error handler */
249         void (*redo) (void);    /* redo handler */
250         void (*done) (int st);  /* done handler */
251 } *cont = NULL;
252
253 #if 0
254 static struct tq_struct mfm_tq = {0, 0, (void (*)(void *)) NULL, 0};
255 #endif
256
257 int number_mfm_drives = 1;
258
259 /* ------------------------------------------------------------------------------------------ */
260 /*
261  * From the HD63463 data sheet from Hitachi Ltd.
262  */
263
264 #define MFM_COMMAND (mfm_addr + 0)
265 #define MFM_DATAOUT (mfm_addr + 1)
266 #define MFM_STATUS  (mfm_addr + 8)
267 #define MFM_DATAIN  (mfm_addr + 9)
268
269 #define CMD_ABT         0xF0    /* Abort */
270 #define CMD_SPC         0xE8    /* Specify */
271 #define CMD_TST         0xE0    /* Test */
272 #define CMD_RCLB        0xC8    /* Recalibrate */
273 #define CMD_SEK         0xC0    /* Seek */
274 #define CMD_WFS         0xAB    /* Write Format Skew */
275 #define CMD_WFM         0xA3    /* Write Format */
276 #define CMD_MTB         0x90    /* Memory to buffer */
277 #define CMD_CMPD        0x88    /* Compare data */
278 #define CMD_WD          0x87    /* Write data */
279 #define CMD_RED         0x70    /* Read erroneous data */
280 #define CMD_RIS         0x68    /* Read ID skew */
281 #define CMD_FID         0x61    /* Find ID */
282 #define CMD_RID         0x60    /* Read ID */
283 #define CMD_BTM         0x50    /* Buffer to memory */
284 #define CMD_CKD         0x48    /* Check data */
285 #define CMD_RD          0x40    /* Read data */
286 #define CMD_OPBW        0x38    /* Open buffer write */
287 #define CMD_OPBR        0x30    /* Open buffer read */
288 #define CMD_CKV         0x28    /* Check drive */
289 #define CMD_CKE         0x20    /* Check ECC */
290 #define CMD_POD         0x18    /* Polling disable */
291 #define CMD_POL         0x10    /* Polling enable */
292 #define CMD_RCAL        0x08    /* Recall */
293
294 #define STAT_BSY        0x8000  /* Busy */
295 #define STAT_CPR        0x4000  /* Command Parameter Rejection */
296 #define STAT_CED        0x2000  /* Command end */
297 #define STAT_SED        0x1000  /* Seek end */
298 #define STAT_DER        0x0800  /* Drive error */
299 #define STAT_ABN        0x0400  /* Abnormal end */
300 #define STAT_POL        0x0200  /* Polling */
301
302 /* ------------------------------------------------------------------------------------------ */
303 #ifdef DEBUG
304 static void console_printf(const char *fmt,...)
305 {
306         static char buffer[2048];       /* Arbitary! */
307         extern void console_print(const char *);
308         unsigned long flags;
309         va_list ap;
310
311         local_irq_save(flags);
312
313         va_start(ap, fmt);
314         vsprintf(buffer, fmt, ap);
315         console_print(buffer);
316         va_end(fmt);
317
318         local_irq_restore(flags);
319 };      /* console_printf */
320
321 #define DBG(x...) console_printf(x)
322 #else
323 #define DBG(x...)
324 #endif
325
326 static void print_status(void)
327 {
328         char *error;
329         static char *errors[] = {
330          "no error",
331          "command aborted",
332          "invalid command",
333          "parameter error",
334          "not initialised",
335          "rejected TEST",
336          "no useld",
337          "write fault",
338          "not ready",
339          "no scp",
340          "in seek",
341          "invalid NCA",
342          "invalid step rate",
343          "seek error",
344          "over run",
345          "invalid PHA",
346          "data field EEC error",
347          "data field CRC error",
348          "error corrected",
349          "data field fatal error",
350          "no data am",
351          "not hit",
352          "ID field CRC error",
353          "time over",
354          "no ID am",
355          "not writable"
356         };
357         if (result[1] < 0x65)
358                 error = errors[result[1] >> 2];
359         else
360                 error = "unknown";
361         printk("(");
362         if (mfm_status & STAT_BSY) printk("BSY ");
363         if (mfm_status & STAT_CPR) printk("CPR ");
364         if (mfm_status & STAT_CED) printk("CED ");
365         if (mfm_status & STAT_SED) printk("SED ");
366         if (mfm_status & STAT_DER) printk("DER ");
367         if (mfm_status & STAT_ABN) printk("ABN ");
368         if (mfm_status & STAT_POL) printk("POL ");
369         printk(") SSB = %X (%s)\n", result[1], error);
370
371 }
372
373 /* ------------------------------------------------------------------------------------- */
374
375 static void issue_command(int command, unsigned char *cmdb, int len)
376 {
377         int status;
378 #ifdef DEBUG
379         int i;
380         console_printf("issue_command: %02X: ", command);
381         for (i = 0; i < len; i++)
382                 console_printf("%02X ", cmdb[i]);
383         console_printf("\n");
384 #endif
385
386         do {
387                 status = inw(MFM_STATUS);
388         } while (status & (STAT_BSY | STAT_POL));
389         DBG("issue_command: status after pol/bsy loop: %02X:\n ", status >> 8);
390
391         if (status & (STAT_CPR | STAT_CED | STAT_SED | STAT_DER | STAT_ABN)) {
392                 outw(CMD_RCAL, MFM_COMMAND);
393                 while (inw(MFM_STATUS) & STAT_BSY);
394         }
395         status = inw(MFM_STATUS);
396         DBG("issue_command: status before parameter issue: %02X:\n ", status >> 8);
397
398         while (len > 0) {
399                 outw(cmdb[1] | (cmdb[0] << 8), MFM_DATAOUT);
400                 len -= 2;
401                 cmdb += 2;
402         }
403         status = inw(MFM_STATUS);
404         DBG("issue_command: status before command issue: %02X:\n ", status >> 8);
405
406         outw(command, MFM_COMMAND);
407         status = inw(MFM_STATUS);
408         DBG("issue_command: status immediately after command issue: %02X:\n ", status >> 8);
409 }
410
411 static void wait_for_completion(void)
412 {
413         while ((mfm_status = inw(MFM_STATUS)) & STAT_BSY);
414 }
415
416 static void wait_for_command_end(void)
417 {
418         int i;
419
420         while (!((mfm_status = inw(MFM_STATUS)) & STAT_CED));
421
422         for (i = 0; i < 16;) {
423                 int in;
424                 in = inw(MFM_DATAIN);
425                 result[i++] = in >> 8;
426                 result[i++] = in;
427         }
428         outw (CMD_RCAL, MFM_COMMAND);
429 }
430
431 /* ------------------------------------------------------------------------------------- */
432
433 static void mfm_rw_intr(void)
434 {
435         int old_status;         /* Holds status on entry, we read to see if the command just finished */
436 #ifdef DEBUG
437         console_printf("mfm_rw_intr...dataleft=%d\n", hdc63463_dataleft);
438         print_status();
439 #endif
440
441   /* Now don't handle the error until BSY drops */
442         if ((mfm_status & (STAT_DER | STAT_ABN)) && ((mfm_status&STAT_BSY)==0)) {
443                 /* Something has gone wrong - let's try that again */
444                 outw(CMD_RCAL, MFM_COMMAND);    /* Clear interrupt condition */
445                 if (cont) {
446                         DBG("mfm_rw_intr: DER/ABN err\n");
447                         cont->error();
448                         cont->redo();
449                 };
450                 return;
451         };
452
453         /* OK so what ever happened it's not an error, now I reckon we are left between
454            a choice of command end or some data which is ready to be collected */
455         /* I think we have to transfer data while the interrupt line is on and its
456            not any other type of interrupt */
457         if (CURRENT->cmd == WRITE) {
458                 extern void hdc63463_writedma(void);
459                 if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) {
460                         printk("mfm_rw_intr: Apparent DMA write request when no more to DMA\n");
461                         if (cont) {
462                                 cont->error();
463                                 cont->redo();
464                         };
465                         return;
466                 };
467                 hdc63463_writedma();
468         } else {
469                 extern void hdc63463_readdma(void);
470                 if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) {
471                         printk("mfm_rw_intr: Apparent DMA read request when no more to DMA\n");
472                         if (cont) {
473                                 cont->error();
474                                 cont->redo();
475                         };
476                         return;
477                 };
478                 DBG("Going to try read dma..............status=0x%x, buffer=%p\n", mfm_status, hdc63463_dataptr);
479                 hdc63463_readdma();
480         };                      /* Read */
481
482         if (hdc63463_dataptr != ((unsigned int) Copy_buffer + 256)) {
483                 /* If we didn't actually manage to get any data on this interrupt - but why? We got the interrupt */
484                 /* Ah - well looking at the status its just when we get command end; so no problem */
485                 /*console_printf("mfm: dataptr mismatch. dataptr=0x%08x Copy_buffer+256=0x%08p\n",
486                    hdc63463_dataptr,Copy_buffer+256);
487                    print_status(); */
488         } else {
489                 Sectors256LeftInCurrent--;
490                 Copy_buffer += 256;
491                 Copy_Sector++;
492
493                 /* We have come to the end of this request */
494                 if (!Sectors256LeftInCurrent) {
495                         DBG("mfm: end_request for CURRENT=0x%p CURRENT(sector=%d current_nr_sectors=%d nr_sectors=%d)\n",
496                                        CURRENT, CURRENT->sector, CURRENT->current_nr_sectors, CURRENT->nr_sectors);
497
498                         CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
499                         CURRENT->sector += CURRENT->current_nr_sectors;
500                         SectorsLeftInRequest -= CURRENT->current_nr_sectors;
501
502                         end_request(CURRENT, 1);
503                         if (SectorsLeftInRequest) {
504                                 hdc63463_dataptr = (unsigned int) CURRENT->buffer;
505                                 Copy_buffer = CURRENT->buffer;
506                                 Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2;
507                                 errors = &(CURRENT->errors);
508                                 /* These should match the present calculations of the next logical sector
509                                    on the device
510                                    Copy_Sector=CURRENT->sector*2; */
511
512                                 if (Copy_Sector != CURRENT->sector * 2)
513 #ifdef DEBUG
514                                         /*console_printf*/printk("mfm: Copy_Sector mismatch. Copy_Sector=%d CURRENT->sector*2=%d\n",
515                                         Copy_Sector, CURRENT->sector * 2);
516 #else
517                                         printk("mfm: Copy_Sector mismatch! Eek!\n");
518 #endif
519                         };      /* CURRENT */
520                 };      /* Sectors256LeftInCurrent */
521         };
522
523         old_status = mfm_status;
524         mfm_status = inw(MFM_STATUS);
525         if (mfm_status & (STAT_DER | STAT_ABN)) {
526                 /* Something has gone wrong - let's try that again */
527                 if (cont) {
528                         DBG("mfm_rw_intr: DER/ABN error\n");
529                         cont->error();
530                         cont->redo();
531                 };
532                 return;
533         };
534
535         /* If this code wasn't entered due to command_end but there is
536            now a command end we must read the command results out. If it was
537            entered like this then mfm_interrupt_handler would have done the
538            job. */
539         if ((!((old_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) &&
540             ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) {
541                 int len = 0;
542                 while (len < 16) {
543                         int in;
544                         in = inw(MFM_DATAIN);
545                         result[len++] = in >> 8;
546                         result[len++] = in;
547                 };
548         };                      /* Result read */
549
550         /*console_printf ("mfm_rw_intr nearexit [%02X]\n", __raw_readb(mfm_IRQPollLoc)); */
551
552         /* If end of command move on */
553         if (mfm_status & (STAT_CED)) {
554                 outw(CMD_RCAL, MFM_COMMAND);    /* Clear interrupt condition */
555                 /* End of command - trigger the next command */
556                 if (cont) {
557                         cont->done(1);
558                 }
559                 DBG("mfm_rw_intr: returned from cont->done\n");
560         } else {
561                 /* Its going to generate another interrupt */
562                 do_mfm = mfm_rw_intr;
563         };
564 }
565
566 static void mfm_setup_rw(void)
567 {
568         DBG("setting up for rw...\n");
569
570         do_mfm = mfm_rw_intr;
571         issue_command(raw_cmd.cmdcode, raw_cmd.cmddata, raw_cmd.cmdlen);
572 }
573
574 static void mfm_recal_intr(void)
575 {
576 #ifdef DEBUG
577         console_printf("recal intr - status = ");
578         print_status();
579 #endif
580         outw(CMD_RCAL, MFM_COMMAND);    /* Clear interrupt condition */
581         if (mfm_status & (STAT_DER | STAT_ABN)) {
582                 printk("recal failed\n");
583                 MFM_DRV_INFO.cylinder = NEED_2_RECAL;
584                 if (cont) {
585                         cont->error();
586                         cont->redo();
587                 }
588                 return;
589         }
590         /* Thats seek end - we are finished */
591         if (mfm_status & STAT_SED) {
592                 issue_command(CMD_POD, NULL, 0);
593                 MFM_DRV_INFO.cylinder = 0;
594                 mfm_seek();
595                 return;
596         }
597         /* Command end without seek end (see data sheet p.20) for parallel seek
598            - we have to send a POL command to wait for the seek */
599         if (mfm_status & STAT_CED) {
600                 do_mfm = mfm_recal_intr;
601                 issue_command(CMD_POL, NULL, 0);
602                 return;
603         }
604         printk("recal: unknown status\n");
605 }
606
607 static void mfm_seek_intr(void)
608 {
609 #ifdef DEBUG
610         console_printf("seek intr - status = ");
611         print_status();
612 #endif
613         outw(CMD_RCAL, MFM_COMMAND);    /* Clear interrupt condition */
614         if (mfm_status & (STAT_DER | STAT_ABN)) {
615                 printk("seek failed\n");
616                 MFM_DRV_INFO.cylinder = NEED_2_RECAL;
617                 if (cont) {
618                         cont->error();
619                         cont->redo();
620                 }
621                 return;
622         }
623         if (mfm_status & STAT_SED) {
624                 issue_command(CMD_POD, NULL, 0);
625                 MFM_DRV_INFO.cylinder = raw_cmd.cylinder;
626                 mfm_seek();
627                 return;
628         }
629         if (mfm_status & STAT_CED) {
630                 do_mfm = mfm_seek_intr;
631                 issue_command(CMD_POL, NULL, 0);
632                 return;
633         }
634         printk("seek: unknown status\n");
635 }
636
637 /* IDEA2 seems to work better - its what RiscOS sets my
638  * disc to - on its SECOND call to specify!
639  */
640 #define IDEA2
641 #ifndef IDEA2
642 #define SPEC_SL 0x16
643 #define SPEC_SH 0xa9            /* Step pulse high=21, Record Length=001 (256 bytes) */
644 #else
645 #define SPEC_SL 0x00            /* OM2 - SL - step pulse low */
646 #define SPEC_SH 0x21            /* Step pulse high=4, Record Length=001 (256 bytes) */
647 #endif
648
649 static void mfm_setupspecify (int drive, unsigned char *cmdb)
650 {
651         cmdb[0]  = 0x1f;                /* OM0 - !SECT,!MOD,!DIF,PADP,ECD,CRCP,CRCI,ACOR */
652         cmdb[1]  = 0xc3;                /* OM1 - DTM,BRST,!CEDM,!SEDM,!DERM,0,AMEX,PSK */
653         cmdb[2]  = SPEC_SL;             /* OM2 - SL - step pulse low */
654         cmdb[3]  = (number_mfm_drives == 1) ? 0x02 : 0x06;      /* 1 or 2 drives */
655         cmdb[4]  = 0xfc | ((mfm_info[drive].cylinders - 1) >> 8);/* RW time over/high part of number of cylinders */
656         cmdb[5]  = mfm_info[drive].cylinders - 1;               /* low part of number of cylinders */
657         cmdb[6]  = mfm_info[drive].heads - 1;                   /* Number of heads */
658         cmdb[7]  = mfm_info[drive].sectors - 1;                 /* Number of sectors */
659         cmdb[8]  = SPEC_SH;
660         cmdb[9]  = 0x0a;                /* gap length 1 */
661         cmdb[10] = 0x0d;                /* gap length 2 */
662         cmdb[11] = 0x0c;                /* gap length 3 */
663         cmdb[12] = (mfm_info[drive].precomp - 1) >> 8;  /* pre comp cylinder */
664         cmdb[13] = mfm_info[drive].precomp - 1;
665         cmdb[14] = (mfm_info[drive].lowcurrent - 1) >> 8;       /* Low current cylinder */
666         cmdb[15] = mfm_info[drive].lowcurrent - 1;
667 }
668
669 static void mfm_specify (void)
670 {
671         unsigned char cmdb[16];
672
673         DBG("specify...dev=%d lastspecified=%d\n", raw_cmd.dev, lastspecifieddrive);
674         mfm_setupspecify (raw_cmd.dev, cmdb);
675
676         issue_command (CMD_SPC, cmdb, 16);
677         /* Ensure that we will do another specify if we move to the other drive */
678         lastspecifieddrive = raw_cmd.dev;
679         wait_for_completion();
680 }
681
682 static void mfm_seek(void)
683 {
684         unsigned char cmdb[4];
685
686         DBG("seeking...\n");
687         if (MFM_DRV_INFO.cylinder < 0) {
688                 do_mfm = mfm_recal_intr;
689                 DBG("mfm_seek: about to call specify\n");
690                 mfm_specify (); /* DAG added this */
691
692                 cmdb[0] = raw_cmd.dev + 1;
693                 cmdb[1] = 0;
694
695                 issue_command(CMD_RCLB, cmdb, 2);
696                 return;
697         }
698         if (MFM_DRV_INFO.cylinder != raw_cmd.cylinder) {
699                 cmdb[0] = raw_cmd.dev + 1;
700                 cmdb[1] = 0;    /* raw_cmd.head; DAG: My data sheet says this should be 0 */
701                 cmdb[2] = raw_cmd.cylinder >> 8;
702                 cmdb[3] = raw_cmd.cylinder;
703
704                 do_mfm = mfm_seek_intr;
705                 issue_command(CMD_SEK, cmdb, 4);
706         } else
707                 mfm_setup_rw();
708 }
709
710 static void mfm_initialise(void)
711 {
712         DBG("init...\n");
713         mfm_seek();
714 }
715
716 static void request_done(int uptodate)
717 {
718         DBG("mfm:request_done\n");
719         if (uptodate) {
720                 unsigned char block[2] = {0, 0};
721
722                 /* Apparently worked - let's check bytes left to DMA */
723                 if (hdc63463_dataleft != (PartFragRead_SectorsLeft * 256)) {
724                         printk("mfm: request_done - dataleft=%d - should be %d - Eek!\n", hdc63463_dataleft, PartFragRead_SectorsLeft * 256);
725                         end_request(CURRENT, 0);
726                         Busy = 0;
727                 };
728                 /* Potentially this means that we've done; but we might be doing
729                    a partial access, (over two cylinders) or we may have a number
730                    of fragments in an image file.  First let's deal with partial accesss
731                  */
732                 if (PartFragRead) {
733                         /* Yep - a partial access */
734
735                         /* and issue the remainder */
736                         issue_request(PartFragRead_RestartBlock, PartFragRead_SectorsLeft, CURRENT);
737                         return;
738                 }
739
740                 /* ah well - perhaps there is another fragment to go */
741
742                 /* Increment pointers/counts to start of next fragment */
743                 if (SectorsLeftInRequest > 0) printk("mfm: SectorsLeftInRequest>0 - Eek! Shouldn't happen!\n");
744
745                 /* No - its the end of the line */
746                 /* end_request's should have happened at the end of sector DMAs */
747                 /* Turns Drive LEDs off - may slow it down? */
748                 if (!elv_next_request(QUEUE))
749                         issue_command(CMD_CKV, block, 2);
750
751                 Busy = 0;
752                 DBG("request_done: About to mfm_request\n");
753                 /* Next one please */
754                 mfm_request();  /* Moved from mfm_rw_intr */
755                 DBG("request_done: returned from mfm_request\n");
756         } else {
757                 printk("mfm:request_done: update=0\n");
758                 end_request(CURRENT, 0);
759                 Busy = 0;
760         }
761 }
762
763 static void error_handler(void)
764 {
765         printk("error detected... status = ");
766         print_status();
767         (*errors)++;
768         if (*errors > MFM_DRV_INFO.errors.abort)
769                 cont->done(0);
770         if (*errors > MFM_DRV_INFO.errors.recal)
771                 MFM_DRV_INFO.cylinder = NEED_2_RECAL;
772 }
773
774 static void rw_interrupt(void)
775 {
776         printk("rw_interrupt\n");
777 }
778
779 static struct cont rw_cont =
780 {
781         rw_interrupt,
782         error_handler,
783         mfm_rerequest,
784         request_done
785 };
786
787 /*
788  * Actually gets round to issuing the request - note everything at this
789  * point is in 256 byte sectors not Linux 512 byte blocks
790  */
791 static void issue_request(unsigned int block, unsigned int nsect,
792                           struct request *req)
793 {
794         struct gendisk *disk = req->rq_disk;
795         struct mfm_info *p = disk->private_data;
796         int track, start_head, start_sector;
797         int sectors_to_next_cyl;
798         dev = p - mfm_info;
799
800         track = block / p->sectors;
801         start_sector = block % p->sectors;
802         start_head = track % p->heads;
803
804         /* First get the number of whole tracks which are free before the next
805            track */
806         sectors_to_next_cyl = (p->heads - (start_head + 1)) * p->sectors;
807         /* Then add in the number of sectors left on this track */
808         sectors_to_next_cyl += (p->sectors - start_sector);
809
810         DBG("issue_request: mfm_info[dev].sectors=%d track=%d\n", p->sectors, track);
811
812         raw_cmd.dev = dev;
813         raw_cmd.sector = start_sector;
814         raw_cmd.head = start_head;
815         raw_cmd.cylinder = track / p->heads;
816         raw_cmd.cmdtype = CURRENT->cmd;
817         raw_cmd.cmdcode = CURRENT->cmd == WRITE ? CMD_WD : CMD_RD;
818         raw_cmd.cmddata[0] = dev + 1;   /* DAG: +1 to get US */
819         raw_cmd.cmddata[1] = raw_cmd.head;
820         raw_cmd.cmddata[2] = raw_cmd.cylinder >> 8;
821         raw_cmd.cmddata[3] = raw_cmd.cylinder;
822         raw_cmd.cmddata[4] = raw_cmd.head;
823         raw_cmd.cmddata[5] = raw_cmd.sector;
824
825         /* Was == and worked - how the heck??? */
826         if (lastspecifieddrive != raw_cmd.dev)
827                 mfm_specify ();
828
829         if (nsect <= sectors_to_next_cyl) {
830                 raw_cmd.cmddata[6] = nsect >> 8;
831                 raw_cmd.cmddata[7] = nsect;
832                 PartFragRead = 0;       /* All in one */
833                 PartFragRead_SectorsLeft = 0;   /* Must set this - used in DMA calcs */
834         } else {
835                 raw_cmd.cmddata[6] = sectors_to_next_cyl >> 8;
836                 raw_cmd.cmddata[7] = sectors_to_next_cyl;
837                 PartFragRead = sectors_to_next_cyl;     /* only do this many this time */
838                 PartFragRead_RestartBlock = block + sectors_to_next_cyl;        /* Where to restart from */
839                 PartFragRead_SectorsLeft = nsect - sectors_to_next_cyl;
840         }
841         raw_cmd.cmdlen = 8;
842
843         /* Setup DMA pointers */
844         hdc63463_dataptr = (unsigned int) Copy_buffer;
845         hdc63463_dataleft = nsect * 256;        /* Better way? */
846
847         DBG("mfm%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx (%p)\n",
848              raw_cmd.dev + 'a', (CURRENT->cmd == READ) ? "read" : "writ",
849                        raw_cmd.cylinder,
850                        raw_cmd.head,
851             raw_cmd.sector, nsect, (unsigned long) Copy_buffer, CURRENT);
852
853         cont = &rw_cont;
854         errors = &(CURRENT->errors);
855 #if 0
856         mfm_tq.routine = (void (*)(void *)) mfm_initialise;
857         queue_task(&mfm_tq, &tq_immediate);
858         mark_bh(IMMEDIATE_BH);
859 #else
860         mfm_initialise();
861 #endif
862 }                               /* issue_request */
863
864 /*
865  * Called when an error has just happened - need to trick mfm_request
866  * into thinking we weren't busy
867  *
868  * Turn off ints - mfm_request expects them this way
869  */
870 static void mfm_rerequest(void)
871 {
872         DBG("mfm_rerequest\n");
873         cli();
874         Busy = 0;
875         mfm_request();
876 }
877
878 static struct gendisk *mfm_gendisk[2];
879
880 static void mfm_request(void)
881 {
882         DBG("mfm_request CURRENT=%p Busy=%d\n", CURRENT, Busy);
883
884         /* If we are still processing then return; we will get called again */
885         if (Busy) {
886                 /* Again seems to be common in 1.3.45 */
887                 /*DBG*/printk("mfm_request: Exiting due to busy\n");
888                 return;
889         }
890         Busy = 1;
891
892         while (1) {
893                 unsigned int block, nsect;
894                 struct gendisk *disk;
895
896                 DBG("mfm_request: loop start\n");
897                 sti();
898
899                 DBG("mfm_request: before !CURRENT\n");
900
901                 if (!CURRENT) {
902                         printk("mfm_request: Exiting due to empty queue (pre)\n");
903                         do_mfm = NULL;
904                         Busy = 0;
905                         return;
906                 }
907
908                 DBG("mfm_request:                 before arg extraction\n");
909
910                 disk = CURRENT->rq_disk;
911                 block = CURRENT->sector;
912                 nsect = CURRENT->nr_sectors;
913                 if (block >= get_capacity(disk) ||
914                     block+nsect > get_capacity(disk)) {
915                         printk("%s: bad access: block=%d, count=%d, nr_sects=%ld\n",
916                                disk->disk_name, block, nsect, get_capacity(disk));
917                         printk("mfm: continue 1\n");
918                         end_request(CURRENT, 0);
919                         Busy = 0;
920                         continue;
921                 }
922
923                 /* DAG: Linux doesn't cope with this - even though it has an array telling
924                    it the hardware block size - silly */
925                 block <<= 1;    /* Now in 256 byte sectors */
926                 nsect <<= 1;    /* Ditto */
927
928                 SectorsLeftInRequest = nsect >> 1;
929                 Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2;
930                 Copy_buffer = CURRENT->buffer;
931                 Copy_Sector = CURRENT->sector << 1;
932
933                 DBG("mfm_request: block after offset=%d\n", block);
934
935                 if (CURRENT->cmd != READ && CURRENT->cmd != WRITE) {
936                         printk("unknown mfm-command %d\n", CURRENT->cmd);
937                         end_request(CURRENT, 0);
938                         Busy = 0;
939                         printk("mfm: continue 4\n");
940                         continue;
941                 }
942                 issue_request(block, nsect, CURRENT);
943
944                 break;
945         }
946         DBG("mfm_request: Dropping out bottom\n");
947 }
948
949 static void do_mfm_request(request_queue_t *q)
950 {
951         DBG("do_mfm_request: about to mfm_request\n");
952         mfm_request();
953 }
954
955 static void mfm_interrupt_handler(int unused, void *dev_id, struct pt_regs *regs)
956 {
957         void (*handler) (void) = do_mfm;
958
959         do_mfm = NULL;
960
961         DBG("mfm_interrupt_handler (handler=0x%p)\n", handler);
962
963         mfm_status = inw(MFM_STATUS);
964
965         /* If CPR (Command Parameter Reject) and not busy it means that the command
966            has some return message to give us */
967         if ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR) {
968                 int len = 0;
969                 while (len < 16) {
970                         int in;
971                         in = inw(MFM_DATAIN);
972                         result[len++] = in >> 8;
973                         result[len++] = in;
974                 }
975         }
976         if (handler) {
977                 handler();
978                 return;
979         }
980         outw (CMD_RCAL, MFM_COMMAND);   /* Clear interrupt condition */
981         printk ("mfm: unexpected interrupt - status = ");
982         print_status ();
983         while (1);
984 }
985
986
987
988
989
990 /*
991  * Tell the user about the drive if we decided it exists.
992  */
993 static void mfm_geometry(int drive)
994 {
995         struct mfm_info *p = mfm_info + drive;
996         struct gendisk *disk = mfm_gendisk[drive];
997         disk->private_data = p;
998         if (p->cylinders)
999                 printk ("%s: %dMB CHS=%d/%d/%d LCC=%d RECOMP=%d\n",
1000                         disk->disk_name,
1001                         p->cylinders * p->heads * p->sectors / 4096,
1002                         p->cylinders, p->heads, p->sectors,
1003                         p->lowcurrent, p->precomp);
1004         set_capacity(disk, p->cylinders * p->heads * p->sectors / 2);
1005 }
1006
1007 #ifdef CONFIG_BLK_DEV_MFM_AUTODETECT
1008 /*
1009  * Attempt to detect a drive and find its geometry.  The drive has already been
1010  * specified...
1011  *
1012  * We first recalibrate the disk, then try to probe sectors, heads and then
1013  * cylinders.  NOTE! the cylinder probe may break drives.  The xd disk driver
1014  * does something along these lines, so I assume that most drives are up to
1015  * this mistreatment...
1016  */
1017 static int mfm_detectdrive (int drive)
1018 {
1019         unsigned int mingeo[3], maxgeo[3];
1020         unsigned int attribute, need_recal = 1;
1021         unsigned char cmdb[8];
1022
1023         memset (mingeo, 0, sizeof (mingeo));
1024         maxgeo[0] = mfm_info[drive].sectors;
1025         maxgeo[1] = mfm_info[drive].heads;
1026         maxgeo[2] = mfm_info[drive].cylinders;
1027
1028         cmdb[0] = drive + 1;
1029         cmdb[6] = 0;
1030         cmdb[7] = 1;
1031         for (attribute = 0; attribute < 3; attribute++) {
1032                 while (mingeo[attribute] != maxgeo[attribute]) {
1033                         unsigned int variable;
1034
1035                         variable = (maxgeo[attribute] + mingeo[attribute]) >> 1;
1036                         cmdb[1] = cmdb[2] = cmdb[3] = cmdb[4] = cmdb[5] = 0;
1037
1038                         if (need_recal) {
1039                                 int tries = 5;
1040
1041                                 do {
1042                                         issue_command (CMD_RCLB, cmdb, 2);
1043                                         wait_for_completion ();
1044                                         wait_for_command_end ();
1045                                         if  (result[1] == 0x20)
1046                                                 break;
1047                                 } while (result[1] && --tries);
1048                                 if (result[1]) {
1049                                         outw (CMD_RCAL, MFM_COMMAND);
1050                                         return 0;
1051                                 }
1052                                 need_recal = 0;
1053                         }
1054
1055                         switch (attribute) {
1056                         case 0:
1057                                 cmdb[5] = variable;
1058                                 issue_command (CMD_CMPD, cmdb, 8);
1059                                 break;
1060                         case 1:
1061                                 cmdb[1] = variable;
1062                                 cmdb[4] = variable;
1063                                 issue_command (CMD_CMPD, cmdb, 8);
1064                                 break;
1065                         case 2:
1066                                 cmdb[2] = variable >> 8;
1067                                 cmdb[3] = variable;
1068                                 issue_command (CMD_SEK, cmdb, 4);
1069                                 break;
1070                         }
1071                         wait_for_completion ();
1072                         wait_for_command_end ();
1073
1074                         switch (result[1]) {
1075                         case 0x00:
1076                         case 0x50:
1077                                 mingeo[attribute] = variable + 1;
1078                                 break;
1079
1080                         case 0x20:
1081                                 outw (CMD_RCAL, MFM_COMMAND);
1082                                 return 0;
1083
1084                         case 0x24:
1085                                 need_recal = 1;
1086                         default:
1087                                 maxgeo[attribute] = variable;
1088                                 break;
1089                         }
1090                 }
1091         }
1092         mfm_info[drive].cylinders  = mingeo[2];
1093         mfm_info[drive].lowcurrent = mingeo[2];
1094         mfm_info[drive].precomp    = mingeo[2] / 2;
1095         mfm_info[drive].heads      = mingeo[1];
1096         mfm_info[drive].sectors    = mingeo[0];
1097         outw (CMD_RCAL, MFM_COMMAND);
1098         return 1;
1099 }
1100 #endif
1101
1102 /*
1103  * Initialise all drive information for this controller.
1104  */
1105 static int mfm_initdrives(void)
1106 {
1107         int drive;
1108
1109         if (number_mfm_drives > MFM_MAXDRIVES) {
1110                 number_mfm_drives = MFM_MAXDRIVES;
1111                 printk("No. of ADFS MFM drives is greater than MFM_MAXDRIVES - you can't have that many!\n");
1112         }
1113
1114         for (drive = 0; drive < number_mfm_drives; drive++) {
1115                 mfm_info[drive].lowcurrent = 1;
1116                 mfm_info[drive].precomp    = 1;
1117                 mfm_info[drive].cylinder   = -1;
1118                 mfm_info[drive].errors.recal  = 0;
1119                 mfm_info[drive].errors.report = 0;
1120                 mfm_info[drive].errors.abort  = 4;
1121
1122 #ifdef CONFIG_BLK_DEV_MFM_AUTODETECT
1123                 mfm_info[drive].cylinders  = 1024;
1124                 mfm_info[drive].heads      = 8;
1125                 mfm_info[drive].sectors    = 64;
1126                 {
1127                         unsigned char cmdb[16];
1128
1129                         mfm_setupspecify (drive, cmdb);
1130                         cmdb[1] &= ~0x81;
1131                         issue_command (CMD_SPC, cmdb, 16);
1132                         wait_for_completion ();
1133                         if (!mfm_detectdrive (drive)) {
1134                                 mfm_info[drive].cylinders = 0;
1135                                 mfm_info[drive].heads     = 0;
1136                                 mfm_info[drive].sectors   = 0;
1137                         }
1138                         cmdb[0] = cmdb[1] = 0;
1139                         issue_command (CMD_CKV, cmdb, 2);
1140                 }
1141 #else
1142                 mfm_info[drive].cylinders  = 1; /* its going to have to figure it out from the partition info */
1143                 mfm_info[drive].heads      = 4;
1144                 mfm_info[drive].sectors    = 32;
1145 #endif
1146         }
1147         return number_mfm_drives;
1148 }
1149
1150
1151
1152 /*
1153  * The 'front' end of the mfm driver follows...
1154  */
1155
1156 static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg)
1157 {
1158         struct mfm_info *p = inode->i_bdev->bd_disk->private_data;
1159         struct hd_geometry *geo = (struct hd_geometry *) arg;
1160         if (cmd != HDIO_GETGEO)
1161                 return -EINVAL;
1162         if (!arg)
1163                 return -EINVAL;
1164         if (put_user (p->heads, &geo->heads))
1165                 return -EFAULT;
1166         if (put_user (p->sectors, &geo->sectors))
1167                 return -EFAULT;
1168         if (put_user (p->cylinders, &geo->cylinders))
1169                 return -EFAULT;
1170         if (put_user (get_start_sect(inode->i_bdev), &geo->start))
1171                 return -EFAULT;
1172         return 0;
1173 }
1174
1175 /*
1176  * This is to handle various kernel command line parameters
1177  * specific to this driver.
1178  */
1179 void mfm_setup(char *str, int *ints)
1180 {
1181         return;
1182 }
1183
1184 /*
1185  * Set the CHS from the ADFS boot block if it is present.  This is not ideal
1186  * since if there are any non-ADFS partitions on the disk, this won't work!
1187  * Hence, I want to get rid of this...
1188  */
1189 void xd_set_geometry(struct block_device *bdev, unsigned char secsptrack,
1190                         unsigned char heads, unsigned int secsize)
1191 {
1192         struct mfm_info *p = bdev->bd_disk->private_data;
1193         int drive = p - mfm_info;
1194         unsigned long disksize = bdev->bd_inode->i_size;
1195
1196         if (p->cylinders == 1) {
1197                 p->sectors = secsptrack;
1198                 p->heads = heads;
1199                 p->cylinders = discsize / (secsptrack * heads * secsize);
1200
1201                 if ((heads < 1) || (p->cylinders > 1024)) {
1202                         printk("%s: Insane disc shape! Setting to 512/4/32\n",
1203                                 bdev->bd_disk->disk_name);
1204
1205                         /* These values are fairly arbitary, but are there so that if your
1206                          * lucky you can pick apart your disc to find out what is going on -
1207                          * I reckon these figures won't hurt MOST drives
1208                          */
1209                         p->sectors = 32;
1210                         p->heads = 4;
1211                         p->cylinders = 512;
1212                 }
1213                 if (raw_cmd.dev == drive)
1214                         mfm_specify ();
1215                 mfm_geometry (drive);
1216         }
1217 }
1218
1219 static struct block_device_operations mfm_fops =
1220 {
1221         .owner          = THIS_MODULE,
1222         .ioctl          = mfm_ioctl,
1223 };
1224
1225 /*
1226  * See if there is a controller at the address presently at mfm_addr
1227  *
1228  * We check to see if the controller is busy - if it is, we abort it first,
1229  * and check that the chip is no longer busy after at least 180 clock cycles.
1230  * We then issue a command and check that the BSY or CPR bits are set.
1231  */
1232 static int mfm_probecontroller (unsigned int mfm_addr)
1233 {
1234         if (inw (MFM_STATUS) & STAT_BSY) {
1235                 outw (CMD_ABT, MFM_COMMAND);
1236                 udelay (50);
1237                 if (inw (MFM_STATUS) & STAT_BSY)
1238                         return 0;
1239         }
1240
1241         if (inw (MFM_STATUS) & STAT_CED)
1242                 outw (CMD_RCAL, MFM_COMMAND);
1243
1244         outw (CMD_SEK, MFM_COMMAND);
1245
1246         if (inw (MFM_STATUS) & (STAT_BSY | STAT_CPR)) {
1247                 unsigned int count = 2000;
1248                 while (inw (MFM_STATUS) & STAT_BSY) {
1249                         udelay (500);
1250                         if (!--count)
1251                                 return 0;
1252                 }
1253
1254                 outw (CMD_RCAL, MFM_COMMAND);
1255         }
1256         return 1;
1257 }
1258
1259 static int mfm_do_init(unsigned char irqmask)
1260 {
1261         int i, ret;
1262
1263         printk("mfm: found at address %08X, interrupt %d\n", mfm_addr, mfm_irq);
1264
1265         ret = -EBUSY;
1266         if (!request_region (mfm_addr, 10, "mfm"))
1267                 goto out1;
1268
1269         ret = register_blkdev(MAJOR_NR, "mfm");
1270         if (ret)
1271                 goto out2;
1272
1273         /* Stuff for the assembler routines to get to */
1274         hdc63463_baseaddress    = ioaddr(mfm_addr);
1275         hdc63463_irqpolladdress = mfm_IRQPollLoc;
1276         hdc63463_irqpollmask    = irqmask;
1277
1278         mfm_queue = blk_init_queue(do_mfm_request, &mfm_lock);
1279         if (!mfm_queue)
1280                 goto out2a;
1281
1282         Busy = 0;
1283         lastspecifieddrive = -1;
1284
1285         mfm_drives = mfm_initdrives();
1286         if (!mfm_drives) {
1287                 ret = -ENODEV;
1288                 goto out3;
1289         }
1290         
1291         for (i = 0; i < mfm_drives; i++) {
1292                 struct gendisk *disk = alloc_disk(64);
1293                 if (!disk)
1294                         goto Enomem;
1295                 disk->major = MAJOR_NR;
1296                 disk->first_minor = i << 6;
1297                 disk->fops = &mfm_fops;
1298                 sprintf(disk->disk_name, "mfm%c", 'a'+i);
1299                 mfm_gendisk[i] = disk;
1300         }
1301
1302         printk("mfm: detected %d hard drive%s\n", mfm_drives,
1303                                 mfm_drives == 1 ? "" : "s");
1304         ret = request_irq(mfm_irq, mfm_interrupt_handler, SA_INTERRUPT, "MFM harddisk", NULL);
1305         if (ret) {
1306                 printk("mfm: unable to get IRQ%d\n", mfm_irq);
1307                 goto out4;
1308         }
1309
1310         if (mfm_irqenable)
1311                 outw(0x80, mfm_irqenable);      /* Required to enable IRQs from MFM podule */
1312
1313         for (i = 0; i < mfm_drives; i++) {
1314                 mfm_geometry(i);
1315                 mfm_gendisk[i]->queue = mfm_queue;
1316                 add_disk(mfm_gendisk[i]);
1317         }
1318         return 0;
1319
1320 out4:
1321         for (i = 0; i < mfm_drives; i++)
1322                 put_disk(mfm_gendisk[i]);
1323 out3:
1324         blk_cleanup_queue(mfm_queue);
1325 out2a:
1326         unregister_blkdev(MAJOR_NR, "mfm");
1327 out2:
1328         release_region(mfm_addr, 10);
1329 out1:
1330         return ret;
1331 Enomem:
1332         while (i--)
1333                 put_disk(mfm_gendisk[i]);
1334         goto out3;
1335 }
1336
1337 static void mfm_do_exit(void)
1338 {
1339         int i;
1340
1341         free_irq(mfm_irq, NULL);
1342         for (i = 0; i < mfm_drives; i++) {
1343                 del_gendisk(mfm_gendisk[i]);
1344                 put_disk(mfm_gendisk[i]);
1345         }
1346         blk_cleanup_queue(mfm_queue);
1347         unregister_blkdev(MAJOR_NR, "mfm");
1348         if (mfm_addr)
1349                 release_region(mfm_addr, 10);
1350 }
1351
1352 static int __devinit mfm_probe(struct expansion_card *ec, struct ecard_id *id)
1353 {
1354         if (mfm_addr)
1355                 return -EBUSY;
1356
1357         mfm_addr        = ecard_address(ec, ECARD_IOC, ECARD_MEDIUM) + 0x800;
1358         mfm_IRQPollLoc  = ioaddr(mfm_addr + 0x400);
1359         mfm_irqenable   = mfm_IRQPollLoc;
1360         mfm_irq         = ec->irq;
1361
1362         return mfm_do_init(0x08);
1363 }
1364
1365 static void __devexit mfm_remove(struct expansion_card *ec)
1366 {
1367         outw (0, mfm_irqenable);        /* Required to enable IRQs from MFM podule */
1368         mfm_do_exit();
1369 }
1370
1371 static const struct ecard_id mfm_cids[] = {
1372         { MANU_ACORN, PROD_ACORN_MFM },
1373         { 0xffff, 0xffff },
1374 };
1375
1376 static struct ecard_driver mfm_driver = {
1377         .probe          = mfm_probe,
1378         .remove         = __devexit(mfm_remove),
1379         .id_table       = mfm_cids,
1380         .drv = {
1381                 .name   = "mfm",
1382         },
1383 };
1384
1385 /*
1386  * Look for a MFM controller - first check the motherboard, then the podules
1387  * The podules have an extra interrupt enable that needs to be played with
1388  *
1389  * The HDC is accessed at MEDIUM IOC speeds.
1390  */
1391 static int __init mfm_init (void)
1392 {
1393         unsigned char irqmask;
1394
1395         if (mfm_probecontroller(ONBOARD_MFM_ADDRESS)) {
1396                 mfm_addr        = ONBOARD_MFM_ADDRESS;
1397                 mfm_IRQPollLoc  = IOC_IRQSTATB;
1398                 mfm_irqenable   = 0;
1399                 mfm_irq         = IRQ_HARDDISK;
1400                 return mfm_do_init(0x08);       /* IL3 pin */
1401         } else {
1402                 return ecard_register_driver(&mfm_driver);
1403         }
1404 }
1405
1406 static void __exit mfm_exit(void)
1407 {
1408         if (mfm_addr == ONBOARD_MFM_ADDRESS)
1409                 mfm_do_exit();
1410         else
1411                 ecard_unregister_driver(&mfm_driver);
1412 }
1413
1414 module_init(mfm_init)
1415 module_exit(mfm_exit)
1416 MODULE_LICENSE("GPL");