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