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