ia64/linux-2.6.18-xen.hg

view drivers/block/amiflop.c @ 897:329ea0ccb344

balloon: try harder to balloon up under memory pressure.

Currently if the balloon driver is unable to increase the guest's
reservation it assumes the failure was due to reaching its full
allocation, gives up on the ballooning operation and records the limit
it reached as the "hard limit". The driver will not try again until
the target is set again (even to the same value).

However it is possible that ballooning has in fact failed due to
memory pressure in the host and therefore it is desirable to keep
attempting to reach the target in case memory becomes available. The
most likely scenario is that some guests are ballooning down while
others are ballooning up and therefore there is temporary memory
pressure while things stabilise. You would not expect a well behaved
toolstack to ask a domain to balloon to more than its allocation nor
would you expect it to deliberately over-commit memory by setting
balloon targets which exceed the total host memory.

This patch drops the concept of a hard limit and causes the balloon
driver to retry increasing the reservation on a timer in the same
manner as when decreasing the reservation.

Also if we partially succeed in increasing the reservation
(i.e. receive less pages than we asked for) then we may as well keep
those pages rather than returning them to Xen.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 05 14:01:20 2009 +0100 (2009-06-05)
parents 831230e53067
children
line source
1 /*
2 * linux/amiga/amiflop.c
3 *
4 * Copyright (C) 1993 Greg Harp
5 * Portions of this driver are based on code contributed by Brad Pepers
6 *
7 * revised 28.5.95 by Joerg Dorchain
8 * - now no bugs(?) any more for both HD & DD
9 * - added support for 40 Track 5.25" drives, 80-track hopefully behaves
10 * like 3.5" dd (no way to test - are there any 5.25" drives out there
11 * that work on an A4000?)
12 * - wrote formatting routine (maybe dirty, but works)
13 *
14 * june/july 1995 added ms-dos support by Joerg Dorchain
15 * (portions based on messydos.device and various contributors)
16 * - currently only 9 and 18 sector disks
17 *
18 * - fixed a bug with the internal trackbuffer when using multiple
19 * disks the same time
20 * - made formatting a bit safer
21 * - added command line and machine based default for "silent" df0
22 *
23 * december 1995 adapted for 1.2.13pl4 by Joerg Dorchain
24 * - works but I think it's inefficient. (look in redo_fd_request)
25 * But the changes were very efficient. (only three and a half lines)
26 *
27 * january 1996 added special ioctl for tracking down read/write problems
28 * - usage ioctl(d, RAW_TRACK, ptr); the raw track buffer (MFM-encoded data
29 * is copied to area. (area should be large enough since no checking is
30 * done - 30K is currently sufficient). return the actual size of the
31 * trackbuffer
32 * - replaced udelays() by a timer (CIAA timer B) for the waits
33 * needed for the disk mechanic.
34 *
35 * february 1996 fixed error recovery and multiple disk access
36 * - both got broken the first time I tampered with the driver :-(
37 * - still not safe, but better than before
38 *
39 * revised Marts 3rd, 1996 by Jes Sorensen for use in the 1.3.28 kernel.
40 * - Minor changes to accept the kdev_t.
41 * - Replaced some more udelays with ms_delays. Udelay is just a loop,
42 * and so the delay will be different depending on the given
43 * processor :-(
44 * - The driver could use a major cleanup because of the new
45 * major/minor handling that came with kdev_t. It seems to work for
46 * the time being, but I can't guarantee that it will stay like
47 * that when we start using 16 (24?) bit minors.
48 *
49 * restructured jan 1997 by Joerg Dorchain
50 * - Fixed Bug accessing multiple disks
51 * - some code cleanup
52 * - added trackbuffer for each drive to speed things up
53 * - fixed some race conditions (who finds the next may send it to me ;-)
54 */
56 #include <linux/module.h>
58 #include <linux/fd.h>
59 #include <linux/hdreg.h>
60 #include <linux/delay.h>
61 #include <linux/init.h>
62 #include <linux/amifdreg.h>
63 #include <linux/amifd.h>
64 #include <linux/buffer_head.h>
65 #include <linux/blkdev.h>
66 #include <linux/elevator.h>
67 #include <linux/interrupt.h>
69 #include <asm/setup.h>
70 #include <asm/uaccess.h>
71 #include <asm/amigahw.h>
72 #include <asm/amigaints.h>
73 #include <asm/irq.h>
75 #undef DEBUG /* print _LOTS_ of infos */
77 #define RAW_IOCTL
78 #ifdef RAW_IOCTL
79 #define IOCTL_RAW_TRACK 0x5254524B /* 'RTRK' */
80 #endif
82 /*
83 * Defines
84 */
86 /*
87 * Error codes
88 */
89 #define FD_OK 0 /* operation succeeded */
90 #define FD_ERROR -1 /* general error (seek, read, write, etc) */
91 #define FD_NOUNIT 1 /* unit does not exist */
92 #define FD_UNITBUSY 2 /* unit already active */
93 #define FD_NOTACTIVE 3 /* unit is not active */
94 #define FD_NOTREADY 4 /* unit is not ready (motor not on/no disk) */
96 #define MFM_NOSYNC 1
97 #define MFM_HEADER 2
98 #define MFM_DATA 3
99 #define MFM_TRACK 4
101 /*
102 * Floppy ID values
103 */
104 #define FD_NODRIVE 0x00000000 /* response when no unit is present */
105 #define FD_DD_3 0xffffffff /* double-density 3.5" (880K) drive */
106 #define FD_HD_3 0x55555555 /* high-density 3.5" (1760K) drive */
107 #define FD_DD_5 0xaaaaaaaa /* double-density 5.25" (440K) drive */
109 static unsigned long int fd_def_df0 = FD_DD_3; /* default for df0 if it doesn't identify */
111 module_param(fd_def_df0, ulong, 0);
112 MODULE_LICENSE("GPL");
114 static struct request_queue *floppy_queue;
115 #define QUEUE (floppy_queue)
116 #define CURRENT elv_next_request(floppy_queue)
118 /*
119 * Macros
120 */
121 #define MOTOR_ON (ciab.prb &= ~DSKMOTOR)
122 #define MOTOR_OFF (ciab.prb |= DSKMOTOR)
123 #define SELECT(mask) (ciab.prb &= ~mask)
124 #define DESELECT(mask) (ciab.prb |= mask)
125 #define SELMASK(drive) (1 << (3 + (drive & 3)))
127 static struct fd_drive_type drive_types[] = {
128 /* code name tr he rdsz wrsz sm pc1 pc2 sd st st*/
129 /* warning: times are now in milliseconds (ms) */
130 { FD_DD_3, "DD 3.5", 80, 2, 14716, 13630, 1, 80,161, 3, 18, 1},
131 { FD_HD_3, "HD 3.5", 80, 2, 28344, 27258, 2, 80,161, 3, 18, 1},
132 { FD_DD_5, "DD 5.25", 40, 2, 14716, 13630, 1, 40, 81, 6, 30, 2},
133 { FD_NODRIVE, "No Drive", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
134 };
135 static int num_dr_types = ARRAY_SIZE(drive_types);
137 static int amiga_read(int), dos_read(int);
138 static void amiga_write(int), dos_write(int);
139 static struct fd_data_type data_types[] = {
140 { "Amiga", 11 , amiga_read, amiga_write},
141 { "MS-Dos", 9, dos_read, dos_write}
142 };
144 /* current info on each unit */
145 static struct amiga_floppy_struct unit[FD_MAX_UNITS];
147 static struct timer_list flush_track_timer[FD_MAX_UNITS];
148 static struct timer_list post_write_timer;
149 static struct timer_list motor_on_timer;
150 static struct timer_list motor_off_timer[FD_MAX_UNITS];
151 static int on_attempts;
153 /* Synchronization of FDC access */
154 /* request loop (trackbuffer) */
155 static volatile int fdc_busy = -1;
156 static volatile int fdc_nested;
157 static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
159 static DECLARE_WAIT_QUEUE_HEAD(motor_wait);
161 static volatile int selected = -1; /* currently selected drive */
163 static int writepending;
164 static int writefromint;
165 static char *raw_buf;
167 static DEFINE_SPINLOCK(amiflop_lock);
169 #define RAW_BUF_SIZE 30000 /* size of raw disk data */
171 /*
172 * These are global variables, as that's the easiest way to give
173 * information to interrupts. They are the data used for the current
174 * request.
175 */
176 static volatile char block_flag;
177 static DECLARE_WAIT_QUEUE_HEAD(wait_fd_block);
179 /* MS-Dos MFM Coding tables (should go quick and easy) */
180 static unsigned char mfmencode[16]={
181 0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15,
182 0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55
183 };
184 static unsigned char mfmdecode[128];
186 /* floppy internal millisecond timer stuff */
187 static volatile int ms_busy = -1;
188 static DECLARE_WAIT_QUEUE_HEAD(ms_wait);
189 #define MS_TICKS ((amiga_eclock+50)/1000)
191 /*
192 * Note that MAX_ERRORS=X doesn't imply that we retry every bad read
193 * max X times - some types of errors increase the errorcount by 2 or
194 * even 3, so we might actually retry only X/2 times before giving up.
195 */
196 #define MAX_ERRORS 12
198 #define custom amiga_custom
200 /* Prevent "aliased" accesses. */
201 static int fd_ref[4] = { 0,0,0,0 };
202 static int fd_device[4] = { 0, 0, 0, 0 };
204 /*
205 * Here come the actual hardware access and helper functions.
206 * They are not reentrant and single threaded because all drives
207 * share the same hardware and the same trackbuffer.
208 */
210 /* Milliseconds timer */
212 static irqreturn_t ms_isr(int irq, void *dummy, struct pt_regs *fp)
213 {
214 ms_busy = -1;
215 wake_up(&ms_wait);
216 return IRQ_HANDLED;
217 }
219 /* all waits are queued up
220 A more generic routine would do a schedule a la timer.device */
221 static void ms_delay(int ms)
222 {
223 unsigned long flags;
224 int ticks;
225 if (ms > 0) {
226 local_irq_save(flags);
227 while (ms_busy == 0)
228 sleep_on(&ms_wait);
229 ms_busy = 0;
230 local_irq_restore(flags);
231 ticks = MS_TICKS*ms-1;
232 ciaa.tblo=ticks%256;
233 ciaa.tbhi=ticks/256;
234 ciaa.crb=0x19; /*count eclock, force load, one-shoot, start */
235 sleep_on(&ms_wait);
236 }
237 }
239 /* Hardware semaphore */
241 /* returns true when we would get the semaphore */
242 static inline int try_fdc(int drive)
243 {
244 drive &= 3;
245 return ((fdc_busy < 0) || (fdc_busy == drive));
246 }
248 static void get_fdc(int drive)
249 {
250 unsigned long flags;
252 drive &= 3;
253 #ifdef DEBUG
254 printk("get_fdc: drive %d fdc_busy %d fdc_nested %d\n",drive,fdc_busy,fdc_nested);
255 #endif
256 local_irq_save(flags);
257 while (!try_fdc(drive))
258 sleep_on(&fdc_wait);
259 fdc_busy = drive;
260 fdc_nested++;
261 local_irq_restore(flags);
262 }
264 static inline void rel_fdc(void)
265 {
266 #ifdef DEBUG
267 if (fdc_nested == 0)
268 printk("fd: unmatched rel_fdc\n");
269 printk("rel_fdc: fdc_busy %d fdc_nested %d\n",fdc_busy,fdc_nested);
270 #endif
271 fdc_nested--;
272 if (fdc_nested == 0) {
273 fdc_busy = -1;
274 wake_up(&fdc_wait);
275 }
276 }
278 static void fd_select (int drive)
279 {
280 unsigned char prb = ~0;
282 drive&=3;
283 #ifdef DEBUG
284 printk("selecting %d\n",drive);
285 #endif
286 if (drive == selected)
287 return;
288 get_fdc(drive);
289 selected = drive;
291 if (unit[drive].track % 2 != 0)
292 prb &= ~DSKSIDE;
293 if (unit[drive].motor == 1)
294 prb &= ~DSKMOTOR;
295 ciab.prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3));
296 ciab.prb = prb;
297 prb &= ~SELMASK(drive);
298 ciab.prb = prb;
299 rel_fdc();
300 }
302 static void fd_deselect (int drive)
303 {
304 unsigned char prb;
305 unsigned long flags;
307 drive&=3;
308 #ifdef DEBUG
309 printk("deselecting %d\n",drive);
310 #endif
311 if (drive != selected) {
312 printk(KERN_WARNING "Deselecting drive %d while %d was selected!\n",drive,selected);
313 return;
314 }
316 get_fdc(drive);
317 local_irq_save(flags);
319 selected = -1;
321 prb = ciab.prb;
322 prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3));
323 ciab.prb = prb;
325 local_irq_restore (flags);
326 rel_fdc();
328 }
330 static void motor_on_callback(unsigned long nr)
331 {
332 if (!(ciaa.pra & DSKRDY) || --on_attempts == 0) {
333 wake_up (&motor_wait);
334 } else {
335 motor_on_timer.expires = jiffies + HZ/10;
336 add_timer(&motor_on_timer);
337 }
338 }
340 static int fd_motor_on(int nr)
341 {
342 nr &= 3;
344 del_timer(motor_off_timer + nr);
346 if (!unit[nr].motor) {
347 unit[nr].motor = 1;
348 fd_select(nr);
350 motor_on_timer.data = nr;
351 mod_timer(&motor_on_timer, jiffies + HZ/2);
353 on_attempts = 10;
354 sleep_on (&motor_wait);
355 fd_deselect(nr);
356 }
358 if (on_attempts == 0) {
359 on_attempts = -1;
360 #if 0
361 printk (KERN_ERR "motor_on failed, turning motor off\n");
362 fd_motor_off (nr);
363 return 0;
364 #else
365 printk (KERN_WARNING "DSKRDY not set after 1.5 seconds - assuming drive is spinning notwithstanding\n");
366 #endif
367 }
369 return 1;
370 }
372 static void fd_motor_off(unsigned long drive)
373 {
374 long calledfromint;
375 #ifdef MODULE
376 long decusecount;
378 decusecount = drive & 0x40000000;
379 #endif
380 calledfromint = drive & 0x80000000;
381 drive&=3;
382 if (calledfromint && !try_fdc(drive)) {
383 /* We would be blocked in an interrupt, so try again later */
384 motor_off_timer[drive].expires = jiffies + 1;
385 add_timer(motor_off_timer + drive);
386 return;
387 }
388 unit[drive].motor = 0;
389 fd_select(drive);
390 udelay (1);
391 fd_deselect(drive);
392 }
394 static void floppy_off (unsigned int nr)
395 {
396 int drive;
398 drive = nr & 3;
399 /* called this way it is always from interrupt */
400 motor_off_timer[drive].data = nr | 0x80000000;
401 mod_timer(motor_off_timer + drive, jiffies + 3*HZ);
402 }
404 static int fd_calibrate(int drive)
405 {
406 unsigned char prb;
407 int n;
409 drive &= 3;
410 get_fdc(drive);
411 if (!fd_motor_on (drive))
412 return 0;
413 fd_select (drive);
414 prb = ciab.prb;
415 prb |= DSKSIDE;
416 prb &= ~DSKDIREC;
417 ciab.prb = prb;
418 for (n = unit[drive].type->tracks/2; n != 0; --n) {
419 if (ciaa.pra & DSKTRACK0)
420 break;
421 prb &= ~DSKSTEP;
422 ciab.prb = prb;
423 prb |= DSKSTEP;
424 udelay (2);
425 ciab.prb = prb;
426 ms_delay(unit[drive].type->step_delay);
427 }
428 ms_delay (unit[drive].type->settle_time);
429 prb |= DSKDIREC;
430 n = unit[drive].type->tracks + 20;
431 for (;;) {
432 prb &= ~DSKSTEP;
433 ciab.prb = prb;
434 prb |= DSKSTEP;
435 udelay (2);
436 ciab.prb = prb;
437 ms_delay(unit[drive].type->step_delay + 1);
438 if ((ciaa.pra & DSKTRACK0) == 0)
439 break;
440 if (--n == 0) {
441 printk (KERN_ERR "fd%d: calibrate failed, turning motor off\n", drive);
442 fd_motor_off (drive);
443 unit[drive].track = -1;
444 rel_fdc();
445 return 0;
446 }
447 }
448 unit[drive].track = 0;
449 ms_delay(unit[drive].type->settle_time);
451 rel_fdc();
452 fd_deselect(drive);
453 return 1;
454 }
456 static int fd_seek(int drive, int track)
457 {
458 unsigned char prb;
459 int cnt;
461 #ifdef DEBUG
462 printk("seeking drive %d to track %d\n",drive,track);
463 #endif
464 drive &= 3;
465 get_fdc(drive);
466 if (unit[drive].track == track) {
467 rel_fdc();
468 return 1;
469 }
470 if (!fd_motor_on(drive)) {
471 rel_fdc();
472 return 0;
473 }
474 if (unit[drive].track < 0 && !fd_calibrate(drive)) {
475 rel_fdc();
476 return 0;
477 }
479 fd_select (drive);
480 cnt = unit[drive].track/2 - track/2;
481 prb = ciab.prb;
482 prb |= DSKSIDE | DSKDIREC;
483 if (track % 2 != 0)
484 prb &= ~DSKSIDE;
485 if (cnt < 0) {
486 cnt = - cnt;
487 prb &= ~DSKDIREC;
488 }
489 ciab.prb = prb;
490 if (track % 2 != unit[drive].track % 2)
491 ms_delay (unit[drive].type->side_time);
492 unit[drive].track = track;
493 if (cnt == 0) {
494 rel_fdc();
495 fd_deselect(drive);
496 return 1;
497 }
498 do {
499 prb &= ~DSKSTEP;
500 ciab.prb = prb;
501 prb |= DSKSTEP;
502 udelay (1);
503 ciab.prb = prb;
504 ms_delay (unit[drive].type->step_delay);
505 } while (--cnt != 0);
506 ms_delay (unit[drive].type->settle_time);
508 rel_fdc();
509 fd_deselect(drive);
510 return 1;
511 }
513 static unsigned long fd_get_drive_id(int drive)
514 {
515 int i;
516 ulong id = 0;
518 drive&=3;
519 get_fdc(drive);
520 /* set up for ID */
521 MOTOR_ON;
522 udelay(2);
523 SELECT(SELMASK(drive));
524 udelay(2);
525 DESELECT(SELMASK(drive));
526 udelay(2);
527 MOTOR_OFF;
528 udelay(2);
529 SELECT(SELMASK(drive));
530 udelay(2);
531 DESELECT(SELMASK(drive));
532 udelay(2);
534 /* loop and read disk ID */
535 for (i=0; i<32; i++) {
536 SELECT(SELMASK(drive));
537 udelay(2);
539 /* read and store value of DSKRDY */
540 id <<= 1;
541 id |= (ciaa.pra & DSKRDY) ? 0 : 1; /* cia regs are low-active! */
543 DESELECT(SELMASK(drive));
544 }
546 rel_fdc();
548 /*
549 * RB: At least A500/A2000's df0: don't identify themselves.
550 * As every (real) Amiga has at least a 3.5" DD drive as df0:
551 * we default to that if df0: doesn't identify as a certain
552 * type.
553 */
554 if(drive == 0 && id == FD_NODRIVE)
555 {
556 id = fd_def_df0;
557 printk(KERN_NOTICE "fd: drive 0 didn't identify, setting default %08lx\n", (ulong)fd_def_df0);
558 }
559 /* return the ID value */
560 return (id);
561 }
563 static irqreturn_t fd_block_done(int irq, void *dummy, struct pt_regs *fp)
564 {
565 if (block_flag)
566 custom.dsklen = 0x4000;
568 if (block_flag == 2) { /* writing */
569 writepending = 2;
570 post_write_timer.expires = jiffies + 1; /* at least 2 ms */
571 post_write_timer.data = selected;
572 add_timer(&post_write_timer);
573 }
574 else { /* reading */
575 block_flag = 0;
576 wake_up (&wait_fd_block);
577 }
578 return IRQ_HANDLED;
579 }
581 static void raw_read(int drive)
582 {
583 drive&=3;
584 get_fdc(drive);
585 while (block_flag)
586 sleep_on(&wait_fd_block);
587 fd_select(drive);
588 /* setup adkcon bits correctly */
589 custom.adkcon = ADK_MSBSYNC;
590 custom.adkcon = ADK_SETCLR|ADK_WORDSYNC|ADK_FAST;
592 custom.dsksync = MFM_SYNC;
594 custom.dsklen = 0;
595 custom.dskptr = (u_char *)ZTWO_PADDR((u_char *)raw_buf);
596 custom.dsklen = unit[drive].type->read_size/sizeof(short) | DSKLEN_DMAEN;
597 custom.dsklen = unit[drive].type->read_size/sizeof(short) | DSKLEN_DMAEN;
599 block_flag = 1;
601 while (block_flag)
602 sleep_on (&wait_fd_block);
604 custom.dsklen = 0;
605 fd_deselect(drive);
606 rel_fdc();
607 }
609 static int raw_write(int drive)
610 {
611 ushort adk;
613 drive&=3;
614 get_fdc(drive); /* corresponds to rel_fdc() in post_write() */
615 if ((ciaa.pra & DSKPROT) == 0) {
616 rel_fdc();
617 return 0;
618 }
619 while (block_flag)
620 sleep_on(&wait_fd_block);
621 fd_select(drive);
622 /* clear adkcon bits */
623 custom.adkcon = ADK_PRECOMP1|ADK_PRECOMP0|ADK_WORDSYNC|ADK_MSBSYNC;
624 /* set appropriate adkcon bits */
625 adk = ADK_SETCLR|ADK_FAST;
626 if ((ulong)unit[drive].track >= unit[drive].type->precomp2)
627 adk |= ADK_PRECOMP1;
628 else if ((ulong)unit[drive].track >= unit[drive].type->precomp1)
629 adk |= ADK_PRECOMP0;
630 custom.adkcon = adk;
632 custom.dsklen = DSKLEN_WRITE;
633 custom.dskptr = (u_char *)ZTWO_PADDR((u_char *)raw_buf);
634 custom.dsklen = unit[drive].type->write_size/sizeof(short) | DSKLEN_DMAEN|DSKLEN_WRITE;
635 custom.dsklen = unit[drive].type->write_size/sizeof(short) | DSKLEN_DMAEN|DSKLEN_WRITE;
637 block_flag = 2;
638 return 1;
639 }
641 /*
642 * to be called at least 2ms after the write has finished but before any
643 * other access to the hardware.
644 */
645 static void post_write (unsigned long drive)
646 {
647 #ifdef DEBUG
648 printk("post_write for drive %ld\n",drive);
649 #endif
650 drive &= 3;
651 custom.dsklen = 0;
652 block_flag = 0;
653 writepending = 0;
654 writefromint = 0;
655 unit[drive].dirty = 0;
656 wake_up(&wait_fd_block);
657 fd_deselect(drive);
658 rel_fdc(); /* corresponds to get_fdc() in raw_write */
659 }
662 /*
663 * The following functions are to convert the block contents into raw data
664 * written to disk and vice versa.
665 * (Add other formats here ;-))
666 */
668 static unsigned long scan_sync(unsigned long raw, unsigned long end)
669 {
670 ushort *ptr = (ushort *)raw, *endp = (ushort *)end;
672 while (ptr < endp && *ptr++ != 0x4489)
673 ;
674 if (ptr < endp) {
675 while (*ptr == 0x4489 && ptr < endp)
676 ptr++;
677 return (ulong)ptr;
678 }
679 return 0;
680 }
682 static inline unsigned long checksum(unsigned long *addr, int len)
683 {
684 unsigned long csum = 0;
686 len /= sizeof(*addr);
687 while (len-- > 0)
688 csum ^= *addr++;
689 csum = ((csum>>1) & 0x55555555) ^ (csum & 0x55555555);
691 return csum;
692 }
694 static unsigned long decode (unsigned long *data, unsigned long *raw,
695 int len)
696 {
697 ulong *odd, *even;
699 /* convert length from bytes to longwords */
700 len >>= 2;
701 odd = raw;
702 even = odd + len;
704 /* prepare return pointer */
705 raw += len * 2;
707 do {
708 *data++ = ((*odd++ & 0x55555555) << 1) | (*even++ & 0x55555555);
709 } while (--len != 0);
711 return (ulong)raw;
712 }
714 struct header {
715 unsigned char magic;
716 unsigned char track;
717 unsigned char sect;
718 unsigned char ord;
719 unsigned char labels[16];
720 unsigned long hdrchk;
721 unsigned long datachk;
722 };
724 static int amiga_read(int drive)
725 {
726 unsigned long raw;
727 unsigned long end;
728 int scnt;
729 unsigned long csum;
730 struct header hdr;
732 drive&=3;
733 raw = (long) raw_buf;
734 end = raw + unit[drive].type->read_size;
736 for (scnt = 0;scnt < unit[drive].dtype->sects * unit[drive].type->sect_mult; scnt++) {
737 if (!(raw = scan_sync(raw, end))) {
738 printk (KERN_INFO "can't find sync for sector %d\n", scnt);
739 return MFM_NOSYNC;
740 }
742 raw = decode ((ulong *)&hdr.magic, (ulong *)raw, 4);
743 raw = decode ((ulong *)&hdr.labels, (ulong *)raw, 16);
744 raw = decode ((ulong *)&hdr.hdrchk, (ulong *)raw, 4);
745 raw = decode ((ulong *)&hdr.datachk, (ulong *)raw, 4);
746 csum = checksum((ulong *)&hdr,
747 (char *)&hdr.hdrchk-(char *)&hdr);
749 #ifdef DEBUG
750 printk ("(%x,%d,%d,%d) (%lx,%lx,%lx,%lx) %lx %lx\n",
751 hdr.magic, hdr.track, hdr.sect, hdr.ord,
752 *(ulong *)&hdr.labels[0], *(ulong *)&hdr.labels[4],
753 *(ulong *)&hdr.labels[8], *(ulong *)&hdr.labels[12],
754 hdr.hdrchk, hdr.datachk);
755 #endif
757 if (hdr.hdrchk != csum) {
758 printk(KERN_INFO "MFM_HEADER: %08lx,%08lx\n", hdr.hdrchk, csum);
759 return MFM_HEADER;
760 }
762 /* verify track */
763 if (hdr.track != unit[drive].track) {
764 printk(KERN_INFO "MFM_TRACK: %d, %d\n", hdr.track, unit[drive].track);
765 return MFM_TRACK;
766 }
768 raw = decode ((ulong *)(unit[drive].trackbuf + hdr.sect*512),
769 (ulong *)raw, 512);
770 csum = checksum((ulong *)(unit[drive].trackbuf + hdr.sect*512), 512);
772 if (hdr.datachk != csum) {
773 printk(KERN_INFO "MFM_DATA: (%x:%d:%d:%d) sc=%d %lx, %lx\n",
774 hdr.magic, hdr.track, hdr.sect, hdr.ord, scnt,
775 hdr.datachk, csum);
776 printk (KERN_INFO "data=(%lx,%lx,%lx,%lx)\n",
777 ((ulong *)(unit[drive].trackbuf+hdr.sect*512))[0],
778 ((ulong *)(unit[drive].trackbuf+hdr.sect*512))[1],
779 ((ulong *)(unit[drive].trackbuf+hdr.sect*512))[2],
780 ((ulong *)(unit[drive].trackbuf+hdr.sect*512))[3]);
781 return MFM_DATA;
782 }
783 }
785 return 0;
786 }
788 static void encode(unsigned long data, unsigned long *dest)
789 {
790 unsigned long data2;
792 data &= 0x55555555;
793 data2 = data ^ 0x55555555;
794 data |= ((data2 >> 1) | 0x80000000) & (data2 << 1);
796 if (*(dest - 1) & 0x00000001)
797 data &= 0x7FFFFFFF;
799 *dest = data;
800 }
802 static void encode_block(unsigned long *dest, unsigned long *src, int len)
803 {
804 int cnt, to_cnt = 0;
805 unsigned long data;
807 /* odd bits */
808 for (cnt = 0; cnt < len / 4; cnt++) {
809 data = src[cnt] >> 1;
810 encode(data, dest + to_cnt++);
811 }
813 /* even bits */
814 for (cnt = 0; cnt < len / 4; cnt++) {
815 data = src[cnt];
816 encode(data, dest + to_cnt++);
817 }
818 }
820 static unsigned long *putsec(int disk, unsigned long *raw, int cnt)
821 {
822 struct header hdr;
823 int i;
825 disk&=3;
826 *raw = (raw[-1]&1) ? 0x2AAAAAAA : 0xAAAAAAAA;
827 raw++;
828 *raw++ = 0x44894489;
830 hdr.magic = 0xFF;
831 hdr.track = unit[disk].track;
832 hdr.sect = cnt;
833 hdr.ord = unit[disk].dtype->sects * unit[disk].type->sect_mult - cnt;
834 for (i = 0; i < 16; i++)
835 hdr.labels[i] = 0;
836 hdr.hdrchk = checksum((ulong *)&hdr,
837 (char *)&hdr.hdrchk-(char *)&hdr);
838 hdr.datachk = checksum((ulong *)(unit[disk].trackbuf+cnt*512), 512);
840 encode_block(raw, (ulong *)&hdr.magic, 4);
841 raw += 2;
842 encode_block(raw, (ulong *)&hdr.labels, 16);
843 raw += 8;
844 encode_block(raw, (ulong *)&hdr.hdrchk, 4);
845 raw += 2;
846 encode_block(raw, (ulong *)&hdr.datachk, 4);
847 raw += 2;
848 encode_block(raw, (ulong *)(unit[disk].trackbuf+cnt*512), 512);
849 raw += 256;
851 return raw;
852 }
854 static void amiga_write(int disk)
855 {
856 unsigned int cnt;
857 unsigned long *ptr = (unsigned long *)raw_buf;
859 disk&=3;
860 /* gap space */
861 for (cnt = 0; cnt < 415 * unit[disk].type->sect_mult; cnt++)
862 *ptr++ = 0xaaaaaaaa;
864 /* sectors */
865 for (cnt = 0; cnt < unit[disk].dtype->sects * unit[disk].type->sect_mult; cnt++)
866 ptr = putsec (disk, ptr, cnt);
867 *(ushort *)ptr = (ptr[-1]&1) ? 0x2AA8 : 0xAAA8;
868 }
871 struct dos_header {
872 unsigned char track, /* 0-80 */
873 side, /* 0-1 */
874 sec, /* 0-...*/
875 len_desc;/* 2 */
876 unsigned short crc; /* on 68000 we got an alignment problem,
877 but this compiler solves it by adding silently
878 adding a pad byte so data won't fit
879 and this took about 3h to discover.... */
880 unsigned char gap1[22]; /* for longword-alignedness (0x4e) */
881 };
883 /* crc routines are borrowed from the messydos-handler */
885 /* excerpt from the messydos-device
886 ; The CRC is computed not only over the actual data, but including
887 ; the SYNC mark (3 * $a1) and the 'ID/DATA - Address Mark' ($fe/$fb).
888 ; As we don't read or encode these fields into our buffers, we have to
889 ; preload the registers containing the CRC with the values they would have
890 ; after stepping over these fields.
891 ;
892 ; How CRCs "really" work:
893 ;
894 ; First, you should regard a bitstring as a series of coefficients of
895 ; polynomials. We calculate with these polynomials in modulo-2
896 ; arithmetic, in which both add and subtract are done the same as
897 ; exclusive-or. Now, we modify our data (a very long polynomial) in
898 ; such a way that it becomes divisible by the CCITT-standard 16-bit
899 ; 16 12 5
900 ; polynomial: x + x + x + 1, represented by $11021. The easiest
901 ; way to do this would be to multiply (using proper arithmetic) our
902 ; datablock with $11021. So we have:
903 ; data * $11021 =
904 ; data * ($10000 + $1021) =
905 ; data * $10000 + data * $1021
906 ; The left part of this is simple: Just add two 0 bytes. But then
907 ; the right part (data $1021) remains difficult and even could have
908 ; a carry into the left part. The solution is to use a modified
909 ; multiplication, which has a result that is not correct, but with
910 ; a difference of any multiple of $11021. We then only need to keep
911 ; the 16 least significant bits of the result.
912 ;
913 ; The following algorithm does this for us:
914 ;
915 ; unsigned char *data, c, crclo, crchi;
916 ; while (not done) {
917 ; c = *data++ + crchi;
918 ; crchi = (@ c) >> 8 + crclo;
919 ; crclo = @ c;
920 ; }
921 ;
922 ; Remember, + is done with EOR, the @ operator is in two tables (high
923 ; and low byte separately), which is calculated as
924 ;
925 ; $1021 * (c & $F0)
926 ; xor $1021 * (c & $0F)
927 ; xor $1021 * (c >> 4) (* is regular multiplication)
928 ;
929 ;
930 ; Anyway, the end result is the same as the remainder of the division of
931 ; the data by $11021. I am afraid I need to study theory a bit more...
934 my only works was to code this from manx to C....
936 */
938 static ushort dos_crc(void * data_a3, int data_d0, int data_d1, int data_d3)
939 {
940 static unsigned char CRCTable1[] = {
941 0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x81,0x91,0xa1,0xb1,0xc1,0xd1,0xe1,0xf1,
942 0x12,0x02,0x32,0x22,0x52,0x42,0x72,0x62,0x93,0x83,0xb3,0xa3,0xd3,0xc3,0xf3,0xe3,
943 0x24,0x34,0x04,0x14,0x64,0x74,0x44,0x54,0xa5,0xb5,0x85,0x95,0xe5,0xf5,0xc5,0xd5,
944 0x36,0x26,0x16,0x06,0x76,0x66,0x56,0x46,0xb7,0xa7,0x97,0x87,0xf7,0xe7,0xd7,0xc7,
945 0x48,0x58,0x68,0x78,0x08,0x18,0x28,0x38,0xc9,0xd9,0xe9,0xf9,0x89,0x99,0xa9,0xb9,
946 0x5a,0x4a,0x7a,0x6a,0x1a,0x0a,0x3a,0x2a,0xdb,0xcb,0xfb,0xeb,0x9b,0x8b,0xbb,0xab,
947 0x6c,0x7c,0x4c,0x5c,0x2c,0x3c,0x0c,0x1c,0xed,0xfd,0xcd,0xdd,0xad,0xbd,0x8d,0x9d,
948 0x7e,0x6e,0x5e,0x4e,0x3e,0x2e,0x1e,0x0e,0xff,0xef,0xdf,0xcf,0xbf,0xaf,0x9f,0x8f,
949 0x91,0x81,0xb1,0xa1,0xd1,0xc1,0xf1,0xe1,0x10,0x00,0x30,0x20,0x50,0x40,0x70,0x60,
950 0x83,0x93,0xa3,0xb3,0xc3,0xd3,0xe3,0xf3,0x02,0x12,0x22,0x32,0x42,0x52,0x62,0x72,
951 0xb5,0xa5,0x95,0x85,0xf5,0xe5,0xd5,0xc5,0x34,0x24,0x14,0x04,0x74,0x64,0x54,0x44,
952 0xa7,0xb7,0x87,0x97,0xe7,0xf7,0xc7,0xd7,0x26,0x36,0x06,0x16,0x66,0x76,0x46,0x56,
953 0xd9,0xc9,0xf9,0xe9,0x99,0x89,0xb9,0xa9,0x58,0x48,0x78,0x68,0x18,0x08,0x38,0x28,
954 0xcb,0xdb,0xeb,0xfb,0x8b,0x9b,0xab,0xbb,0x4a,0x5a,0x6a,0x7a,0x0a,0x1a,0x2a,0x3a,
955 0xfd,0xed,0xdd,0xcd,0xbd,0xad,0x9d,0x8d,0x7c,0x6c,0x5c,0x4c,0x3c,0x2c,0x1c,0x0c,
956 0xef,0xff,0xcf,0xdf,0xaf,0xbf,0x8f,0x9f,0x6e,0x7e,0x4e,0x5e,0x2e,0x3e,0x0e,0x1e
957 };
959 static unsigned char CRCTable2[] = {
960 0x00,0x21,0x42,0x63,0x84,0xa5,0xc6,0xe7,0x08,0x29,0x4a,0x6b,0x8c,0xad,0xce,0xef,
961 0x31,0x10,0x73,0x52,0xb5,0x94,0xf7,0xd6,0x39,0x18,0x7b,0x5a,0xbd,0x9c,0xff,0xde,
962 0x62,0x43,0x20,0x01,0xe6,0xc7,0xa4,0x85,0x6a,0x4b,0x28,0x09,0xee,0xcf,0xac,0x8d,
963 0x53,0x72,0x11,0x30,0xd7,0xf6,0x95,0xb4,0x5b,0x7a,0x19,0x38,0xdf,0xfe,0x9d,0xbc,
964 0xc4,0xe5,0x86,0xa7,0x40,0x61,0x02,0x23,0xcc,0xed,0x8e,0xaf,0x48,0x69,0x0a,0x2b,
965 0xf5,0xd4,0xb7,0x96,0x71,0x50,0x33,0x12,0xfd,0xdc,0xbf,0x9e,0x79,0x58,0x3b,0x1a,
966 0xa6,0x87,0xe4,0xc5,0x22,0x03,0x60,0x41,0xae,0x8f,0xec,0xcd,0x2a,0x0b,0x68,0x49,
967 0x97,0xb6,0xd5,0xf4,0x13,0x32,0x51,0x70,0x9f,0xbe,0xdd,0xfc,0x1b,0x3a,0x59,0x78,
968 0x88,0xa9,0xca,0xeb,0x0c,0x2d,0x4e,0x6f,0x80,0xa1,0xc2,0xe3,0x04,0x25,0x46,0x67,
969 0xb9,0x98,0xfb,0xda,0x3d,0x1c,0x7f,0x5e,0xb1,0x90,0xf3,0xd2,0x35,0x14,0x77,0x56,
970 0xea,0xcb,0xa8,0x89,0x6e,0x4f,0x2c,0x0d,0xe2,0xc3,0xa0,0x81,0x66,0x47,0x24,0x05,
971 0xdb,0xfa,0x99,0xb8,0x5f,0x7e,0x1d,0x3c,0xd3,0xf2,0x91,0xb0,0x57,0x76,0x15,0x34,
972 0x4c,0x6d,0x0e,0x2f,0xc8,0xe9,0x8a,0xab,0x44,0x65,0x06,0x27,0xc0,0xe1,0x82,0xa3,
973 0x7d,0x5c,0x3f,0x1e,0xf9,0xd8,0xbb,0x9a,0x75,0x54,0x37,0x16,0xf1,0xd0,0xb3,0x92,
974 0x2e,0x0f,0x6c,0x4d,0xaa,0x8b,0xe8,0xc9,0x26,0x07,0x64,0x45,0xa2,0x83,0xe0,0xc1,
975 0x1f,0x3e,0x5d,0x7c,0x9b,0xba,0xd9,0xf8,0x17,0x36,0x55,0x74,0x93,0xb2,0xd1,0xf0
976 };
978 /* look at the asm-code - what looks in C a bit strange is almost as good as handmade */
979 register int i;
980 register unsigned char *CRCT1, *CRCT2, *data, c, crch, crcl;
982 CRCT1=CRCTable1;
983 CRCT2=CRCTable2;
984 data=data_a3;
985 crcl=data_d1;
986 crch=data_d0;
987 for (i=data_d3; i>=0; i--) {
988 c = (*data++) ^ crch;
989 crch = CRCT1[c] ^ crcl;
990 crcl = CRCT2[c];
991 }
992 return (crch<<8)|crcl;
993 }
995 static inline ushort dos_hdr_crc (struct dos_header *hdr)
996 {
997 return dos_crc(&(hdr->track), 0xb2, 0x30, 3); /* precomputed magic */
998 }
1000 static inline ushort dos_data_crc(unsigned char *data)
1002 return dos_crc(data, 0xe2, 0x95 ,511); /* precomputed magic */
1005 static inline unsigned char dos_decode_byte(ushort word)
1007 register ushort w2;
1008 register unsigned char byte;
1009 register unsigned char *dec = mfmdecode;
1011 w2=word;
1012 w2>>=8;
1013 w2&=127;
1014 byte = dec[w2];
1015 byte <<= 4;
1016 w2 = word & 127;
1017 byte |= dec[w2];
1018 return byte;
1021 static unsigned long dos_decode(unsigned char *data, unsigned short *raw, int len)
1023 int i;
1025 for (i = 0; i < len; i++)
1026 *data++=dos_decode_byte(*raw++);
1027 return ((ulong)raw);
1030 #ifdef DEBUG
1031 static void dbg(unsigned long ptr)
1033 printk("raw data @%08lx: %08lx, %08lx ,%08lx, %08lx\n", ptr,
1034 ((ulong *)ptr)[0], ((ulong *)ptr)[1],
1035 ((ulong *)ptr)[2], ((ulong *)ptr)[3]);
1037 #endif
1039 static int dos_read(int drive)
1041 unsigned long end;
1042 unsigned long raw;
1043 int scnt;
1044 unsigned short crc,data_crc[2];
1045 struct dos_header hdr;
1047 drive&=3;
1048 raw = (long) raw_buf;
1049 end = raw + unit[drive].type->read_size;
1051 for (scnt=0; scnt < unit[drive].dtype->sects * unit[drive].type->sect_mult; scnt++) {
1052 do { /* search for the right sync of each sec-hdr */
1053 if (!(raw = scan_sync (raw, end))) {
1054 printk(KERN_INFO "dos_read: no hdr sync on "
1055 "track %d, unit %d for sector %d\n",
1056 unit[drive].track,drive,scnt);
1057 return MFM_NOSYNC;
1059 #ifdef DEBUG
1060 dbg(raw);
1061 #endif
1062 } while (*((ushort *)raw)!=0x5554); /* loop usually only once done */
1063 raw+=2; /* skip over headermark */
1064 raw = dos_decode((unsigned char *)&hdr,(ushort *) raw,8);
1065 crc = dos_hdr_crc(&hdr);
1067 #ifdef DEBUG
1068 printk("(%3d,%d,%2d,%d) %x\n", hdr.track, hdr.side,
1069 hdr.sec, hdr.len_desc, hdr.crc);
1070 #endif
1072 if (crc != hdr.crc) {
1073 printk(KERN_INFO "dos_read: MFM_HEADER %04x,%04x\n",
1074 hdr.crc, crc);
1075 return MFM_HEADER;
1077 if (hdr.track != unit[drive].track/unit[drive].type->heads) {
1078 printk(KERN_INFO "dos_read: MFM_TRACK %d, %d\n",
1079 hdr.track,
1080 unit[drive].track/unit[drive].type->heads);
1081 return MFM_TRACK;
1084 if (hdr.side != unit[drive].track%unit[drive].type->heads) {
1085 printk(KERN_INFO "dos_read: MFM_SIDE %d, %d\n",
1086 hdr.side,
1087 unit[drive].track%unit[drive].type->heads);
1088 return MFM_TRACK;
1091 if (hdr.len_desc != 2) {
1092 printk(KERN_INFO "dos_read: unknown sector len "
1093 "descriptor %d\n", hdr.len_desc);
1094 return MFM_DATA;
1096 #ifdef DEBUG
1097 printk("hdr accepted\n");
1098 #endif
1099 if (!(raw = scan_sync (raw, end))) {
1100 printk(KERN_INFO "dos_read: no data sync on track "
1101 "%d, unit %d for sector%d, disk sector %d\n",
1102 unit[drive].track, drive, scnt, hdr.sec);
1103 return MFM_NOSYNC;
1105 #ifdef DEBUG
1106 dbg(raw);
1107 #endif
1109 if (*((ushort *)raw)!=0x5545) {
1110 printk(KERN_INFO "dos_read: no data mark after "
1111 "sync (%d,%d,%d,%d) sc=%d\n",
1112 hdr.track,hdr.side,hdr.sec,hdr.len_desc,scnt);
1113 return MFM_NOSYNC;
1116 raw+=2; /* skip data mark (included in checksum) */
1117 raw = dos_decode((unsigned char *)(unit[drive].trackbuf + (hdr.sec - 1) * 512), (ushort *) raw, 512);
1118 raw = dos_decode((unsigned char *)data_crc,(ushort *) raw,4);
1119 crc = dos_data_crc(unit[drive].trackbuf + (hdr.sec - 1) * 512);
1121 if (crc != data_crc[0]) {
1122 printk(KERN_INFO "dos_read: MFM_DATA (%d,%d,%d,%d) "
1123 "sc=%d, %x %x\n", hdr.track, hdr.side,
1124 hdr.sec, hdr.len_desc, scnt,data_crc[0], crc);
1125 printk(KERN_INFO "data=(%lx,%lx,%lx,%lx,...)\n",
1126 ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[0],
1127 ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[1],
1128 ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[2],
1129 ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[3]);
1130 return MFM_DATA;
1133 return 0;
1136 static inline ushort dos_encode_byte(unsigned char byte)
1138 register unsigned char *enc, b2, b1;
1139 register ushort word;
1141 enc=mfmencode;
1142 b1=byte;
1143 b2=b1>>4;
1144 b1&=15;
1145 word=enc[b2] <<8 | enc [b1];
1146 return (word|((word&(256|64)) ? 0: 128));
1149 static void dos_encode_block(ushort *dest, unsigned char *src, int len)
1151 int i;
1153 for (i = 0; i < len; i++) {
1154 *dest=dos_encode_byte(*src++);
1155 *dest|=((dest[-1]&1)||(*dest&0x4000))? 0: 0x8000;
1156 dest++;
1160 static unsigned long *ms_putsec(int drive, unsigned long *raw, int cnt)
1162 static struct dos_header hdr={0,0,0,2,0,
1163 {78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78}};
1164 int i;
1165 static ushort crc[2]={0,0x4e4e};
1167 drive&=3;
1168 /* id gap 1 */
1169 /* the MFM word before is always 9254 */
1170 for(i=0;i<6;i++)
1171 *raw++=0xaaaaaaaa;
1172 /* 3 sync + 1 headermark */
1173 *raw++=0x44894489;
1174 *raw++=0x44895554;
1176 /* fill in the variable parts of the header */
1177 hdr.track=unit[drive].track/unit[drive].type->heads;
1178 hdr.side=unit[drive].track%unit[drive].type->heads;
1179 hdr.sec=cnt+1;
1180 hdr.crc=dos_hdr_crc(&hdr);
1182 /* header (without "magic") and id gap 2*/
1183 dos_encode_block((ushort *)raw,(unsigned char *) &hdr.track,28);
1184 raw+=14;
1186 /*id gap 3 */
1187 for(i=0;i<6;i++)
1188 *raw++=0xaaaaaaaa;
1190 /* 3 syncs and 1 datamark */
1191 *raw++=0x44894489;
1192 *raw++=0x44895545;
1194 /* data */
1195 dos_encode_block((ushort *)raw,
1196 (unsigned char *)unit[drive].trackbuf+cnt*512,512);
1197 raw+=256;
1199 /*data crc + jd's special gap (long words :-/) */
1200 crc[0]=dos_data_crc(unit[drive].trackbuf+cnt*512);
1201 dos_encode_block((ushort *) raw,(unsigned char *)crc,4);
1202 raw+=2;
1204 /* data gap */
1205 for(i=0;i<38;i++)
1206 *raw++=0x92549254;
1208 return raw; /* wrote 652 MFM words */
1211 static void dos_write(int disk)
1213 int cnt;
1214 unsigned long raw = (unsigned long) raw_buf;
1215 unsigned long *ptr=(unsigned long *)raw;
1217 disk&=3;
1218 /* really gap4 + indexgap , but we write it first and round it up */
1219 for (cnt=0;cnt<425;cnt++)
1220 *ptr++=0x92549254;
1222 /* the following is just guessed */
1223 if (unit[disk].type->sect_mult==2) /* check for HD-Disks */
1224 for(cnt=0;cnt<473;cnt++)
1225 *ptr++=0x92549254;
1227 /* now the index marks...*/
1228 for (cnt=0;cnt<20;cnt++)
1229 *ptr++=0x92549254;
1230 for (cnt=0;cnt<6;cnt++)
1231 *ptr++=0xaaaaaaaa;
1232 *ptr++=0x52245224;
1233 *ptr++=0x52245552;
1234 for (cnt=0;cnt<20;cnt++)
1235 *ptr++=0x92549254;
1237 /* sectors */
1238 for(cnt = 0; cnt < unit[disk].dtype->sects * unit[disk].type->sect_mult; cnt++)
1239 ptr=ms_putsec(disk,ptr,cnt);
1241 *(ushort *)ptr = 0xaaa8; /* MFM word before is always 0x9254 */
1244 /*
1245 * Here comes the high level stuff (i.e. the filesystem interface)
1246 * and helper functions.
1247 * Normally this should be the only part that has to be adapted to
1248 * different kernel versions.
1249 */
1251 /* FIXME: this assumes the drive is still spinning -
1252 * which is only true if we complete writing a track within three seconds
1253 */
1254 static void flush_track_callback(unsigned long nr)
1256 nr&=3;
1257 writefromint = 1;
1258 if (!try_fdc(nr)) {
1259 /* we might block in an interrupt, so try again later */
1260 flush_track_timer[nr].expires = jiffies + 1;
1261 add_timer(flush_track_timer + nr);
1262 return;
1264 get_fdc(nr);
1265 (*unit[nr].dtype->write_fkt)(nr);
1266 if (!raw_write(nr)) {
1267 printk (KERN_NOTICE "floppy disk write protected\n");
1268 writefromint = 0;
1269 writepending = 0;
1271 rel_fdc();
1274 static int non_int_flush_track (unsigned long nr)
1276 unsigned long flags;
1278 nr&=3;
1279 writefromint = 0;
1280 del_timer(&post_write_timer);
1281 get_fdc(nr);
1282 if (!fd_motor_on(nr)) {
1283 writepending = 0;
1284 rel_fdc();
1285 return 0;
1287 local_irq_save(flags);
1288 if (writepending != 2) {
1289 local_irq_restore(flags);
1290 (*unit[nr].dtype->write_fkt)(nr);
1291 if (!raw_write(nr)) {
1292 printk (KERN_NOTICE "floppy disk write protected "
1293 "in write!\n");
1294 writepending = 0;
1295 return 0;
1297 while (block_flag == 2)
1298 sleep_on (&wait_fd_block);
1300 else {
1301 local_irq_restore(flags);
1302 ms_delay(2); /* 2 ms post_write delay */
1303 post_write(nr);
1305 rel_fdc();
1306 return 1;
1309 static int get_track(int drive, int track)
1311 int error, errcnt;
1313 drive&=3;
1314 if (unit[drive].track == track)
1315 return 0;
1316 get_fdc(drive);
1317 if (!fd_motor_on(drive)) {
1318 rel_fdc();
1319 return -1;
1322 if (unit[drive].dirty == 1) {
1323 del_timer (flush_track_timer + drive);
1324 non_int_flush_track (drive);
1326 errcnt = 0;
1327 while (errcnt < MAX_ERRORS) {
1328 if (!fd_seek(drive, track))
1329 return -1;
1330 raw_read(drive);
1331 error = (*unit[drive].dtype->read_fkt)(drive);
1332 if (error == 0) {
1333 rel_fdc();
1334 return 0;
1336 /* Read Error Handling: recalibrate and try again */
1337 unit[drive].track = -1;
1338 errcnt++;
1340 rel_fdc();
1341 return -1;
1344 static void redo_fd_request(void)
1346 unsigned int cnt, block, track, sector;
1347 int drive;
1348 struct amiga_floppy_struct *floppy;
1349 char *data;
1350 unsigned long flags;
1352 repeat:
1353 if (!CURRENT) {
1354 /* Nothing left to do */
1355 return;
1358 floppy = CURRENT->rq_disk->private_data;
1359 drive = floppy - unit;
1361 /* Here someone could investigate to be more efficient */
1362 for (cnt = 0; cnt < CURRENT->current_nr_sectors; cnt++) {
1363 #ifdef DEBUG
1364 printk("fd: sector %ld + %d requested for %s\n",
1365 CURRENT->sector,cnt,
1366 (CURRENT->cmd==READ)?"read":"write");
1367 #endif
1368 block = CURRENT->sector + cnt;
1369 if ((int)block > floppy->blocks) {
1370 end_request(CURRENT, 0);
1371 goto repeat;
1374 track = block / (floppy->dtype->sects * floppy->type->sect_mult);
1375 sector = block % (floppy->dtype->sects * floppy->type->sect_mult);
1376 data = CURRENT->buffer + 512 * cnt;
1377 #ifdef DEBUG
1378 printk("access to track %d, sector %d, with buffer at "
1379 "0x%08lx\n", track, sector, data);
1380 #endif
1382 if ((rq_data_dir(CURRENT) != READ) && (rq_data_dir(CURRENT) != WRITE)) {
1383 printk(KERN_WARNING "do_fd_request: unknown command\n");
1384 end_request(CURRENT, 0);
1385 goto repeat;
1387 if (get_track(drive, track) == -1) {
1388 end_request(CURRENT, 0);
1389 goto repeat;
1392 switch (rq_data_dir(CURRENT)) {
1393 case READ:
1394 memcpy(data, floppy->trackbuf + sector * 512, 512);
1395 break;
1397 case WRITE:
1398 memcpy(floppy->trackbuf + sector * 512, data, 512);
1400 /* keep the drive spinning while writes are scheduled */
1401 if (!fd_motor_on(drive)) {
1402 end_request(CURRENT, 0);
1403 goto repeat;
1405 /*
1406 * setup a callback to write the track buffer
1407 * after a short (1 tick) delay.
1408 */
1409 local_irq_save(flags);
1411 floppy->dirty = 1;
1412 /* reset the timer */
1413 mod_timer (flush_track_timer + drive, jiffies + 1);
1414 local_irq_restore(flags);
1415 break;
1418 CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
1419 CURRENT->sector += CURRENT->current_nr_sectors;
1421 end_request(CURRENT, 1);
1422 goto repeat;
1425 static void do_fd_request(request_queue_t * q)
1427 redo_fd_request();
1430 static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1432 int drive = MINOR(bdev->bd_dev) & 3;
1434 geo->heads = unit[drive].type->heads;
1435 geo->sectors = unit[drive].dtype->sects * unit[drive].type->sect_mult;
1436 geo->cylinders = unit[drive].type->tracks;
1437 return 0;
1440 static int fd_ioctl(struct inode *inode, struct file *filp,
1441 unsigned int cmd, unsigned long param)
1443 int drive = iminor(inode) & 3;
1444 static struct floppy_struct getprm;
1445 void __user *argp = (void __user *)param;
1447 switch(cmd){
1448 case FDFMTBEG:
1449 get_fdc(drive);
1450 if (fd_ref[drive] > 1) {
1451 rel_fdc();
1452 return -EBUSY;
1454 fsync_bdev(inode->i_bdev);
1455 if (fd_motor_on(drive) == 0) {
1456 rel_fdc();
1457 return -ENODEV;
1459 if (fd_calibrate(drive) == 0) {
1460 rel_fdc();
1461 return -ENXIO;
1463 floppy_off(drive);
1464 rel_fdc();
1465 break;
1466 case FDFMTTRK:
1467 if (param < unit[drive].type->tracks * unit[drive].type->heads)
1469 get_fdc(drive);
1470 if (fd_seek(drive,param) != 0){
1471 memset(unit[drive].trackbuf, FD_FILL_BYTE,
1472 unit[drive].dtype->sects * unit[drive].type->sect_mult * 512);
1473 non_int_flush_track(drive);
1475 floppy_off(drive);
1476 rel_fdc();
1478 else
1479 return -EINVAL;
1480 break;
1481 case FDFMTEND:
1482 floppy_off(drive);
1483 invalidate_bdev(inode->i_bdev, 0);
1484 break;
1485 case FDGETPRM:
1486 memset((void *)&getprm, 0, sizeof (getprm));
1487 getprm.track=unit[drive].type->tracks;
1488 getprm.head=unit[drive].type->heads;
1489 getprm.sect=unit[drive].dtype->sects * unit[drive].type->sect_mult;
1490 getprm.size=unit[drive].blocks;
1491 if (copy_to_user(argp, &getprm, sizeof(struct floppy_struct)))
1492 return -EFAULT;
1493 break;
1494 case FDSETPRM:
1495 case FDDEFPRM:
1496 return -EINVAL;
1497 case FDFLUSH: /* unconditionally, even if not needed */
1498 del_timer (flush_track_timer + drive);
1499 non_int_flush_track(drive);
1500 break;
1501 #ifdef RAW_IOCTL
1502 case IOCTL_RAW_TRACK:
1503 if (copy_to_user(argp, raw_buf, unit[drive].type->read_size))
1504 return -EFAULT;
1505 else
1506 return unit[drive].type->read_size;
1507 #endif
1508 default:
1509 printk(KERN_DEBUG "fd_ioctl: unknown cmd %d for drive %d.",
1510 cmd, drive);
1511 return -ENOSYS;
1513 return 0;
1516 static void fd_probe(int dev)
1518 unsigned long code;
1519 int type;
1520 int drive;
1522 drive = dev & 3;
1523 code = fd_get_drive_id(drive);
1525 /* get drive type */
1526 for (type = 0; type < num_dr_types; type++)
1527 if (drive_types[type].code == code)
1528 break;
1530 if (type >= num_dr_types) {
1531 printk(KERN_WARNING "fd_probe: unsupported drive type "
1532 "%08lx found\n", code);
1533 unit[drive].type = &drive_types[num_dr_types-1]; /* FD_NODRIVE */
1534 return;
1537 unit[drive].type = drive_types + type;
1538 unit[drive].track = -1;
1540 unit[drive].disk = -1;
1541 unit[drive].motor = 0;
1542 unit[drive].busy = 0;
1543 unit[drive].status = -1;
1546 /*
1547 * floppy_open check for aliasing (/dev/fd0 can be the same as
1548 * /dev/PS0 etc), and disallows simultaneous access to the same
1549 * drive with different device numbers.
1550 */
1551 static int floppy_open(struct inode *inode, struct file *filp)
1553 int drive = iminor(inode) & 3;
1554 int system = (iminor(inode) & 4) >> 2;
1555 int old_dev;
1556 unsigned long flags;
1558 old_dev = fd_device[drive];
1560 if (fd_ref[drive] && old_dev != system)
1561 return -EBUSY;
1563 if (filp && filp->f_mode & 3) {
1564 check_disk_change(inode->i_bdev);
1565 if (filp->f_mode & 2 ) {
1566 int wrprot;
1568 get_fdc(drive);
1569 fd_select (drive);
1570 wrprot = !(ciaa.pra & DSKPROT);
1571 fd_deselect (drive);
1572 rel_fdc();
1574 if (wrprot)
1575 return -EROFS;
1579 local_irq_save(flags);
1580 fd_ref[drive]++;
1581 fd_device[drive] = system;
1582 local_irq_restore(flags);
1584 unit[drive].dtype=&data_types[system];
1585 unit[drive].blocks=unit[drive].type->heads*unit[drive].type->tracks*
1586 data_types[system].sects*unit[drive].type->sect_mult;
1587 set_capacity(unit[drive].gendisk, unit[drive].blocks);
1589 printk(KERN_INFO "fd%d: accessing %s-disk with %s-layout\n",drive,
1590 unit[drive].type->name, data_types[system].name);
1592 return 0;
1595 static int floppy_release(struct inode * inode, struct file * filp)
1597 int drive = iminor(inode) & 3;
1599 if (unit[drive].dirty == 1) {
1600 del_timer (flush_track_timer + drive);
1601 non_int_flush_track (drive);
1604 if (!fd_ref[drive]--) {
1605 printk(KERN_CRIT "floppy_release with fd_ref == 0");
1606 fd_ref[drive] = 0;
1608 #ifdef MODULE
1609 /* the mod_use counter is handled this way */
1610 floppy_off (drive | 0x40000000);
1611 #endif
1612 return 0;
1615 /*
1616 * floppy-change is never called from an interrupt, so we can relax a bit
1617 * here, sleep etc. Note that floppy-on tries to set current_DOR to point
1618 * to the desired drive, but it will probably not survive the sleep if
1619 * several floppies are used at the same time: thus the loop.
1620 */
1621 static int amiga_floppy_change(struct gendisk *disk)
1623 struct amiga_floppy_struct *p = disk->private_data;
1624 int drive = p - unit;
1625 int changed;
1626 static int first_time = 1;
1628 if (first_time)
1629 changed = first_time--;
1630 else {
1631 get_fdc(drive);
1632 fd_select (drive);
1633 changed = !(ciaa.pra & DSKCHANGE);
1634 fd_deselect (drive);
1635 rel_fdc();
1638 if (changed) {
1639 fd_probe(drive);
1640 p->track = -1;
1641 p->dirty = 0;
1642 writepending = 0; /* if this was true before, too bad! */
1643 writefromint = 0;
1644 return 1;
1646 return 0;
1649 static struct block_device_operations floppy_fops = {
1650 .owner = THIS_MODULE,
1651 .open = floppy_open,
1652 .release = floppy_release,
1653 .ioctl = fd_ioctl,
1654 .getgeo = fd_getgeo,
1655 .media_changed = amiga_floppy_change,
1656 };
1658 static int __init fd_probe_drives(void)
1660 int drive,drives,nomem;
1662 printk(KERN_INFO "FD: probing units\n" KERN_INFO "found ");
1663 drives=0;
1664 nomem=0;
1665 for(drive=0;drive<FD_MAX_UNITS;drive++) {
1666 struct gendisk *disk;
1667 fd_probe(drive);
1668 if (unit[drive].type->code == FD_NODRIVE)
1669 continue;
1670 disk = alloc_disk(1);
1671 if (!disk) {
1672 unit[drive].type->code = FD_NODRIVE;
1673 continue;
1675 unit[drive].gendisk = disk;
1676 drives++;
1677 if ((unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL)) == NULL) {
1678 printk("no mem for ");
1679 unit[drive].type = &drive_types[num_dr_types - 1]; /* FD_NODRIVE */
1680 drives--;
1681 nomem = 1;
1683 printk("fd%d ",drive);
1684 disk->major = FLOPPY_MAJOR;
1685 disk->first_minor = drive;
1686 disk->fops = &floppy_fops;
1687 sprintf(disk->disk_name, "fd%d", drive);
1688 disk->private_data = &unit[drive];
1689 disk->queue = floppy_queue;
1690 set_capacity(disk, 880*2);
1691 add_disk(disk);
1693 if ((drives > 0) || (nomem == 0)) {
1694 if (drives == 0)
1695 printk("no drives");
1696 printk("\n");
1697 return drives;
1699 printk("\n");
1700 return -ENOMEM;
1703 static struct kobject *floppy_find(dev_t dev, int *part, void *data)
1705 int drive = *part & 3;
1706 if (unit[drive].type->code == FD_NODRIVE)
1707 return NULL;
1708 *part = 0;
1709 return get_disk(unit[drive].gendisk);
1712 int __init amiga_floppy_init(void)
1714 int i, ret;
1716 if (!AMIGAHW_PRESENT(AMI_FLOPPY))
1717 return -ENXIO;
1719 if (register_blkdev(FLOPPY_MAJOR,"fd"))
1720 return -EBUSY;
1722 /*
1723 * We request DSKPTR, DSKLEN and DSKDATA only, because the other
1724 * floppy registers are too spreaded over the custom register space
1725 */
1726 ret = -EBUSY;
1727 if (!request_mem_region(CUSTOM_PHYSADDR+0x20, 8, "amiflop [Paula]")) {
1728 printk("fd: cannot get floppy registers\n");
1729 goto out_blkdev;
1732 ret = -ENOMEM;
1733 if ((raw_buf = (char *)amiga_chip_alloc (RAW_BUF_SIZE, "Floppy")) ==
1734 NULL) {
1735 printk("fd: cannot get chip mem buffer\n");
1736 goto out_memregion;
1739 ret = -EBUSY;
1740 if (request_irq(IRQ_AMIGA_DSKBLK, fd_block_done, 0, "floppy_dma", NULL)) {
1741 printk("fd: cannot get irq for dma\n");
1742 goto out_irq;
1745 if (request_irq(IRQ_AMIGA_CIAA_TB, ms_isr, 0, "floppy_timer", NULL)) {
1746 printk("fd: cannot get irq for timer\n");
1747 goto out_irq2;
1750 ret = -ENOMEM;
1751 floppy_queue = blk_init_queue(do_fd_request, &amiflop_lock);
1752 if (!floppy_queue)
1753 goto out_queue;
1755 ret = -ENXIO;
1756 if (fd_probe_drives() < 1) /* No usable drives */
1757 goto out_probe;
1759 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
1760 floppy_find, NULL, NULL);
1762 /* initialize variables */
1763 init_timer(&motor_on_timer);
1764 motor_on_timer.expires = 0;
1765 motor_on_timer.data = 0;
1766 motor_on_timer.function = motor_on_callback;
1767 for (i = 0; i < FD_MAX_UNITS; i++) {
1768 init_timer(&motor_off_timer[i]);
1769 motor_off_timer[i].expires = 0;
1770 motor_off_timer[i].data = i|0x80000000;
1771 motor_off_timer[i].function = fd_motor_off;
1772 init_timer(&flush_track_timer[i]);
1773 flush_track_timer[i].expires = 0;
1774 flush_track_timer[i].data = i;
1775 flush_track_timer[i].function = flush_track_callback;
1777 unit[i].track = -1;
1780 init_timer(&post_write_timer);
1781 post_write_timer.expires = 0;
1782 post_write_timer.data = 0;
1783 post_write_timer.function = post_write;
1785 for (i = 0; i < 128; i++)
1786 mfmdecode[i]=255;
1787 for (i = 0; i < 16; i++)
1788 mfmdecode[mfmencode[i]]=i;
1790 /* make sure that disk DMA is enabled */
1791 custom.dmacon = DMAF_SETCLR | DMAF_DISK;
1793 /* init ms timer */
1794 ciaa.crb = 8; /* one-shot, stop */
1795 return 0;
1797 out_probe:
1798 blk_cleanup_queue(floppy_queue);
1799 out_queue:
1800 free_irq(IRQ_AMIGA_CIAA_TB, NULL);
1801 out_irq2:
1802 free_irq(IRQ_AMIGA_DSKBLK, NULL);
1803 out_irq:
1804 amiga_chip_free(raw_buf);
1805 out_memregion:
1806 release_mem_region(CUSTOM_PHYSADDR+0x20, 8);
1807 out_blkdev:
1808 unregister_blkdev(FLOPPY_MAJOR,"fd");
1809 return ret;
1812 #ifdef MODULE
1814 int init_module(void)
1816 if (!MACH_IS_AMIGA)
1817 return -ENXIO;
1818 return amiga_floppy_init();
1821 #if 0 /* not safe to unload */
1822 void cleanup_module(void)
1824 int i;
1826 for( i = 0; i < FD_MAX_UNITS; i++) {
1827 if (unit[i].type->code != FD_NODRIVE) {
1828 del_gendisk(unit[i].gendisk);
1829 put_disk(unit[i].gendisk);
1830 kfree(unit[i].trackbuf);
1833 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
1834 free_irq(IRQ_AMIGA_CIAA_TB, NULL);
1835 free_irq(IRQ_AMIGA_DSKBLK, NULL);
1836 custom.dmacon = DMAF_DISK; /* disable DMA */
1837 amiga_chip_free(raw_buf);
1838 blk_cleanup_queue(floppy_queue);
1839 release_mem_region(CUSTOM_PHYSADDR+0x20, 8);
1840 unregister_blkdev(FLOPPY_MAJOR, "fd");
1842 #endif
1844 #else
1845 static int __init amiga_floppy_setup (char *str)
1847 int n;
1848 if (!MACH_IS_AMIGA)
1849 return 0;
1850 if (!get_option(&str, &n))
1851 return 0;
1852 printk (KERN_INFO "amiflop: Setting default df0 to %x\n", n);
1853 fd_def_df0 = n;
1854 return 1;
1857 __setup("floppy=", amiga_floppy_setup);
1858 #endif