1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
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
131
132#ifndef HDIO_GETGEO
133#define HDIO_GETGEO 0x301
134struct hd_geometry {
135 unsigned char heads;
136 unsigned char sectors;
137 unsigned short cylinders;
138 unsigned long start;
139};
140#endif
141
142
143
144
145
146
147
148#define MFM_MAXDRIVES 2
149
150
151
152#define ONBOARD_MFM_ADDRESS ((0x002d0000 >> 2) | 0x80000000)
153
154
155
156#ifndef DEBUG
157
158#endif
159
160
161
162static const card_ids mfm_cids[] = {
163 { MANU_ACORN, PROD_ACORN_MFM },
164 { 0xffff, 0xffff }
165};
166
167
168
169
170
171
172
173
174
175struct mfm_info {
176 unsigned char sectors;
177 unsigned char heads;
178 unsigned short cylinders;
179 unsigned short lowcurrent;
180 unsigned short precomp;
181#define NO_TRACK -1
182#define NEED_1_RECAL -2
183#define NEED_2_RECAL -3
184 int cylinder;
185 unsigned int access_count;
186 unsigned int busy;
187 struct {
188 char recal;
189 char report;
190 char abort;
191 } errors;
192} mfm_info[MFM_MAXDRIVES];
193
194#define MFM_DRV_INFO mfm_info[raw_cmd.dev]
195
196static struct hd_struct mfm[MFM_MAXDRIVES << 6];
197static int mfm_sizes[MFM_MAXDRIVES << 6];
198static int mfm_blocksizes[MFM_MAXDRIVES << 6];
199static int mfm_sectsizes[MFM_MAXDRIVES << 6];
200static DECLARE_WAIT_QUEUE_HEAD(mfm_wait_open);
201
202
203extern unsigned int hdc63463_baseaddress;
204extern unsigned int hdc63463_irqpolladdress;
205extern unsigned int hdc63463_irqpollmask;
206extern unsigned int hdc63463_dataptr;
207extern int hdc63463_dataleft;
208
209
210
211
212static int lastspecifieddrive;
213static unsigned Busy;
214
215static unsigned int PartFragRead;
216
217
218
219
220static unsigned int PartFragRead_RestartBlock;
221static unsigned int PartFragRead_SectorsLeft;
222
223static int Sectors256LeftInCurrent;
224static int SectorsLeftInRequest;
225static int Copy_Sector;
226
227static char *Copy_buffer;
228
229
230static void mfm_seek(void);
231static void mfm_rerequest(void);
232static void mfm_request(void);
233static int mfm_reread_partitions(kdev_t dev);
234static void mfm_specify (void);
235static void issue_request(int dev, unsigned int block, unsigned int nsect,
236 struct request *req);
237
238static unsigned int mfm_addr;
239static unsigned int mfm_IRQPollLoc;
240static unsigned int mfm_irqenable;
241static unsigned char mfm_irq;
242static int mfm_drives = 0;
243static int mfm_status = 0;
244static int *errors;
245
246static struct rawcmd {
247 unsigned int dev;
248 unsigned int cylinder;
249 unsigned int head;
250 unsigned int sector;
251 unsigned int cmdtype;
252 unsigned int cmdcode;
253 unsigned char cmddata[16];
254 unsigned int cmdlen;
255} raw_cmd;
256
257static unsigned char result[16];
258
259static struct cont {
260 void (*interrupt) (void);
261 void (*error) (void);
262 void (*redo) (void);
263 void (*done) (int st);
264} *cont = NULL;
265
266#if 0
267static struct tq_struct mfm_tq = {0, 0, (void (*)(void *)) NULL, 0};
268#endif
269
270int number_mfm_drives = 1;
271
272
273
274
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
283#define CMD_SPC 0xE8
284#define CMD_TST 0xE0
285#define CMD_RCLB 0xC8
286#define CMD_SEK 0xC0
287#define CMD_WFS 0xAB
288#define CMD_WFM 0xA3
289#define CMD_MTB 0x90
290#define CMD_CMPD 0x88
291#define CMD_WD 0x87
292#define CMD_RED 0x70
293#define CMD_RIS 0x68
294#define CMD_FID 0x61
295#define CMD_RID 0x60
296#define CMD_BTM 0x50
297#define CMD_CKD 0x48
298#define CMD_RD 0x40
299#define CMD_OPBW 0x38
300#define CMD_OPBR 0x30
301#define CMD_CKV 0x28
302#define CMD_CKE 0x20
303#define CMD_POD 0x18
304#define CMD_POL 0x10
305#define CMD_RCAL 0x08
306
307#define STAT_BSY 0x8000
308#define STAT_CPR 0x4000
309#define STAT_CED 0x2000
310#define STAT_SED 0x1000
311#define STAT_DER 0x0800
312#define STAT_ABN 0x0400
313#define STAT_POL 0x0200
314
315
316#ifdef DEBUG
317static void console_printf(const char *fmt,...)
318{
319 static char buffer[2048];
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};
333
334#define DBG(x...) console_printf(x)
335#else
336#define DBG(x...)
337#endif
338
339static 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
388static 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
424static void wait_for_completion(void)
425{
426 while ((mfm_status = inw(MFM_STATUS)) & STAT_BSY);
427}
428
429static 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
446static void mfm_rw_intr(void)
447{
448 int old_status;
449#ifdef DEBUG
450 console_printf("mfm_rw_intr...dataleft=%d\n", hdc63463_dataleft);
451 print_status();
452#endif
453
454
455 if ((mfm_status & (STAT_DER | STAT_ABN)) && ((mfm_status&STAT_BSY)==0)) {
456
457 outw(CMD_RCAL, MFM_COMMAND);
458 if (cont) {
459 DBG("mfm_rw_intr: DER/ABN err\n");
460 cont->error();
461 cont->redo();
462 };
463 return;
464 };
465
466
467
468
469
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 };
494
495 if (hdc63463_dataptr != ((unsigned int) Copy_buffer + 256)) {
496
497
498
499
500
501 } else {
502 Sectors256LeftInCurrent--;
503 Copy_buffer += 256;
504 Copy_Sector++;
505
506
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
522
523
524
525 if (Copy_Sector != CURRENT->sector * 2)
526#ifdef DEBUG
527 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 };
533 };
534 };
535
536 old_status = mfm_status;
537 mfm_status = inw(MFM_STATUS);
538 if (mfm_status & (STAT_DER | STAT_ABN)) {
539
540 if (cont) {
541 DBG("mfm_rw_intr: DER/ABN error\n");
542 cont->error();
543 cont->redo();
544 };
545 return;
546 };
547
548
549
550
551
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 };
562
563
564
565
566 if (mfm_status & (STAT_CED)) {
567 outw(CMD_RCAL, MFM_COMMAND);
568
569 if (cont) {
570 cont->done(1);
571 }
572 DBG("mfm_rw_intr: returned from cont->done\n");
573 } else {
574
575 SET_INTR(mfm_rw_intr);
576 };
577}
578
579static 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
587static 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);
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
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
611
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
620static 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);
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
651
652
653#define IDEA2
654#ifndef IDEA2
655#define SPEC_SL 0x16
656#define SPEC_SH 0xa9
657#else
658#define SPEC_SL 0x00
659#define SPEC_SH 0x21
660#endif
661
662static void mfm_setupspecify (int drive, unsigned char *cmdb)
663{
664 cmdb[0] = 0x1f;
665 cmdb[1] = 0xc3;
666 cmdb[2] = SPEC_SL;
667 cmdb[3] = (number_mfm_drives == 1) ? 0x02 : 0x06;
668 cmdb[4] = 0xfc | ((mfm_info[drive].cylinders - 1) >> 8);
669 cmdb[5] = mfm_info[drive].cylinders - 1;
670 cmdb[6] = mfm_info[drive].heads - 1;
671 cmdb[7] = mfm_info[drive].sectors - 1;
672 cmdb[8] = SPEC_SH;
673 cmdb[9] = 0x0a;
674 cmdb[10] = 0x0d;
675 cmdb[11] = 0x0c;
676 cmdb[12] = (mfm_info[drive].precomp - 1) >> 8;
677 cmdb[13] = mfm_info[drive].precomp - 1;
678 cmdb[14] = (mfm_info[drive].lowcurrent - 1) >> 8;
679 cmdb[15] = mfm_info[drive].lowcurrent - 1;
680}
681
682static 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
691 lastspecifieddrive = raw_cmd.dev;
692 wait_for_completion();
693}
694
695static 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 ();
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;
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
723static void mfm_initialise(void)
724{
725 DBG("init...\n");
726 mfm_seek();
727}
728
729static void request_done(int uptodate)
730{
731 DBG("mfm:request_done\n");
732 if (uptodate) {
733 unsigned char block[2] = {0, 0};
734
735
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
742
743
744
745 if (PartFragRead) {
746
747
748
749 issue_request(MINOR(CURRENT->rq_dev), PartFragRead_RestartBlock, PartFragRead_SectorsLeft, CURRENT);
750 return;
751 }
752
753
754
755
756 if (SectorsLeftInRequest > 0) printk("mfm: SectorsLeftInRequest>0 - Eek! Shouldn't happen!\n");
757
758
759
760
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
767 mfm_request();
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
776static 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
787static void rw_interrupt(void)
788{
789 printk("rw_interrupt\n");
790}
791
792static struct cont rw_cont =
793{
794 rw_interrupt,
795 error_handler,
796 mfm_rerequest,
797 request_done
798};
799
800
801
802
803
804static 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
817
818 sectors_to_next_cyl = (mfm_info[dev].heads - (start_head + 1)) * mfm_info[dev].sectors;
819
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;
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
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;
845 PartFragRead_SectorsLeft = 0;
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;
850 PartFragRead_RestartBlock = block + sectors_to_next_cyl;
851 PartFragRead_SectorsLeft = nsect - sectors_to_next_cyl;
852 }
853 raw_cmd.cmdlen = 8;
854
855
856 hdc63463_dataptr = (unsigned int) Copy_buffer;
857 hdc63463_dataleft = nsect * 256;
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}
875
876
877
878
879
880
881
882static void mfm_rerequest(void)
883{
884 DBG("mfm_rerequest\n");
885 cli();
886 Busy = 0;
887 mfm_request();
888}
889
890static 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
901
902 return;
903 }
904
905
906 if (Busy) {
907
908 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 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
954
955 block <<= 1;
956 nsect <<= 1;
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
979static void do_mfm_request(request_queue_t *q)
980{
981 DBG("do_mfm_request: about to mfm_request\n");
982 mfm_request();
983}
984
985static 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
996
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);
1011 printk ("mfm: unexpected interrupt - status = ");
1012 print_status ();
1013 while (1);
1014}
1015
1016
1017
1018
1019
1020
1021
1022
1023static 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
1035
1036
1037
1038
1039
1040
1041
1042static 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
1129
1130static 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;
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
1179
1180
1181static 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
1243static 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
1259
1260
1261static 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
1269
1270
1271void mfm_setup(char *str, int *ints)
1272{
1273 return;
1274}
1275
1276
1277
1278
1279
1280
1281void 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
1295
1296
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
1310static 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
1320static 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
1328static void mfm_geninit (void)
1329{
1330 int i;
1331
1332 for (i = 0; i < (MFM_MAXDRIVES << 6); i++) {
1333
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);
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
1361static struct expansion_card *ecs;
1362
1363
1364
1365
1366
1367
1368
1369
1370static 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
1399
1400
1401
1402
1403int 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;
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
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;
1449
1450 add_gendisk(&mfm_gendisk);
1451
1452 Busy = 0;
1453 lastspecifieddrive = -1;
1454
1455 mfm_geninit();
1456 return 0;
1457}
1458
1459
1460
1461
1462
1463
1464static 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
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
1499EXPORT_NO_SYMBOLS;
1500MODULE_LICENSE("GPL");
1501
1502int init_module(void)
1503{
1504 return mfm_init();
1505}
1506
1507void cleanup_module(void)
1508{
1509 if (ecs && mfm_irqenable)
1510 outw (0, mfm_irqenable);
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