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