fd.c revision 1.4 1 /*-
2 * Copyright (c) 1993, 1994 Charles Hannum.
3 * Copyright (c) 1990 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Don Ahn.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * from: @(#)fd.c 7.4 (Berkeley) 5/25/91
38 */
39 /*
40 * Copyright (c) 1994 Brad Pepers
41 * All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement:
53 * This product includes software developed by Brad Pepers
54 * 4. The name of the author may not be used to endorse or promote products
55 * derived from this software without specific prior written permission
56 *
57 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
58 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
59 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
60 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
61 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
62 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
63 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
64 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
65 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
66 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
67 *
68 * $Id: fd.c,v 1.4 1994/04/22 02:20:48 chopps Exp $
69 *
70 *
71 */
72
73 /*
74 * floppy interface
75 */
76
77 #include "fd.h"
78 #if NFD > 0
79
80 #include <sys/param.h>
81 #include <sys/systm.h>
82 #include <sys/buf.h>
83 #include <sys/dkstat.h>
84 #include <sys/disklabel.h>
85 #include <sys/malloc.h>
86 #include <sys/proc.h>
87 #include <sys/reboot.h>
88 #include <sys/file.h>
89 #include <sys/ioctl.h>
90
91 #include <amiga/dev/device.h>
92 #include <amiga/amiga/cia.h>
93 #include <amiga/amiga/custom.h>
94
95 #define UNIT(x) (minor(x) & 3)
96 #define b_cylin b_resid
97 #define FDBLK 512
98 #define MAX_SECTS 22
99 #define IMMED_WRITE 0
100
101 int fdattach();
102 struct driver fddriver = {
103 fdattach, "fd",
104 };
105
106 /* defines */
107 #define MFM_SYNC 0x4489
108 #define DSKLEN_DMAEN (1<<15)
109 #define DSKLEN_WRITE (1<<14)
110
111 /* drive type values */
112 #define FD_NONE 0xffffffff
113 #define FD_DD_3 0x00000000 /* double-density 3.5" (880K) */
114 #define FD_HD_3 0xaaaaaaaa /* high-density 3.5" (1760K) */
115 #define FD_DD_5 0x55555555 /* double-density 5.25" (440K) */
116
117 struct fd_type {
118 int id;
119 char *name;
120 int tracks;
121 int heads;
122 int read_size;
123 int write_size;
124 int gap_size;
125 int sect_mult;
126 int precomp1;
127 int precomp2;
128 int step_delay;
129 int side_time;
130 int settle_time;
131 };
132
133 struct fd_type drive_types[] = {
134 /* id name tr he rdsz wrsz gap sm pc1 pc2 sd st st */
135 { FD_DD_3, "DD 3.5\"", 80, 2, 14716, 13630, 414, 1, 80, 161, 3, 2, 18 },
136 { FD_HD_3, "HD 3.5\"", 80, 2, 29432, 27260, 828, 2, 80, 161, 3, 2, 18 },
137 { FD_DD_5, "DD 5.25\"",40, 2, 14716, 13630, 414, 1, 40, 80, 3, 2, 18 },
138 { FD_NONE, "No Drive", 0, }
139 };
140 int num_dr_types = sizeof(drive_types) / sizeof(drive_types[0]);
141
142 /*
143 * Per drive structure.
144 * N per controller (presently 4) (DRVS_PER_CTLR)
145 */
146 #define DRVS_PER_CTLR 4
147 struct fd_data {
148 int fdu; /* This unit number */
149 struct buf head; /* Head of buf chain */
150 struct buf rhead; /* Raw head of buf chain */
151 int type; /* Drive type */
152 struct fd_type *ft; /* Pointer to type descriptor */
153 int flags;
154 #define FDF_OPEN 0x01 /* it's open */
155 int skip;
156 int sects; /* number of sectors in a track */
157 int size; /* size of disk in sectors */
158 int side; /* current side disk is on */
159 int dir; /* current direction of stepping */
160 int cyl; /* current cylinder disk is on */
161 int buf_track;
162 int buf_dirty;
163 char *buf_data;
164 char *buf_labels;
165 int write_cnt;
166 };
167
168 /*
169 * Per controller structure.
170 */
171 struct fdc_data
172 {
173 int fdcu; /* our unit number */
174 struct fd_data *fd; /* drive we are currently doing work for */
175 int motor_fdu; /* drive that has its motor on */
176 int state;
177 int saved;
178 int retry;
179 struct fd_data fd_data[DRVS_PER_CTLR];
180 };
181 struct fdc_data fdc_data[NFD];
182
183 /*
184 * Throughout this file the following conventions will be used:
185 *
186 * fd is a pointer to the fd_data struct for the drive in question
187 * fdc is a pointer to the fdc_data struct for the controller
188 * fdu is the floppy drive unit number
189 * fdcu is the floppy controller unit number
190 * fdsu is the floppy drive unit number on that controller. (sub-unit)
191 */
192 typedef int fdu_t;
193 typedef int fdcu_t;
194 typedef int fdsu_t;
195 typedef struct fd_data *fd_p;
196 typedef struct fdc_data *fdc_p;
197
198 /*
199 * protos.
200 */
201 static int delay __P((int));
202 void encode __P((u_long, u_long *, u_long *));
203 void fd_step __P((void));
204 void fd_seek __P((fd_p, int));
205 void correct __P((u_long *));
206 void fd_probe __P((fd_p));
207 void fd_turnon __P((fdc_p, fdu_t));
208 void fd_turnoff __P((fdc_p));
209 void track_read __P((fdc_p, fd_p, int));
210 void fd_timeout __P((fdc_p));
211 void fd_motor_to __P((fdcu_t));
212 void fd_motor_on __P((fdc_p, fdu_t));
213 void track_write __P((fdc_p, fd_p));
214 void amiga_write __P((fd_p));
215 void fd_calibrate __P((fd_p));
216 void encode_block __P((u_long *, u_char *, int, u_long *));
217 void fd_select_dir __P((fd_p, int));
218 void fd_pseudointr __P((fdc_p));
219 void fd_select_side __P((fd_p, int));
220
221 u_long scan_sync __P((u_long, u_long, int));
222 u_long encode_long __P((u_long, u_long *));
223 u_long loop_read_id __P((int));
224 u_long get_drive_id __P((int));
225
226 int fdstate __P((fdc_p));
227 int retrier __P((fdc_p));
228 int amiga_read __P((fd_p));
229 int get_drive_type __P((u_long));
230
231 /* device routines */
232 int Fdopen __P((dev_t, int));
233 int fdsize __P((dev_t));
234 int fdioctl __P((dev_t, int, caddr_t, int, struct proc *));
235 int fdclose __P((dev_t, int));
236 int fdattach __P((struct amiga_device *));
237
238 void fdintr __P((fdcu_t));
239 void fdstart __P((fdc_p));
240 void fdstrategy __P((struct buf *bp));
241
242 #define DEVIDLE 0
243 #define FINDWORK 1
244 #define DOSEEK 2
245 #define DO_IO 3
246 #define DONE_IO 4
247 #define WAIT_READ 5
248 #define WAIT_WRITE 6
249 #define DELAY_WRITE 7
250 #define RECALCOMPLETE 8
251 #define STARTRECAL 9
252 #define RESETCTLR 10
253 #define SEEKWAIT 11
254 #define RECALWAIT 12
255 #define MOTORWAIT 13
256
257 #undef DEBUG
258
259 #ifdef DEBUG
260
261 char *fdstates[] =
262 {
263 "DEVIDLE",
264 "FINDWORK",
265 "DOSEEK",
266 "DO_IO",
267 "DONE_IO",
268 "WAIT_READ",
269 "WAIT_WRITE",
270 "DELAY_WRITE",
271 "RECALCOMPLETE",
272 "STARTRECAL",
273 "RESETCTLR",
274 "SEEKWAIT",
275 "RECALWAIT",
276 "MOTORWAIT",
277 };
278
279 #define TRACE0(arg) if (fd_debug == 1) printf(arg)
280 #define TRACE1(arg1,arg2) if (fd_debug == 1) printf(arg1,arg2)
281
282 #else /* !DEBUG */
283
284 #define TRACE0(arg)
285 #define TRACE1(arg1,arg2)
286
287 #endif /* !DEBUG */
288
289 extern int hz;
290
291 unsigned char *raw_buf = NULL;
292 #ifdef DEBUG
293 int fd_debug = 1;
294 #else
295 int fd_debug = 0;
296 #endif
297
298 /*
299 * Floppy Support Routines
300 */
301 #define MOTOR_ON (ciab.prb &= ~CIAB_PRB_MTR)
302 #define MOTOR_OFF (ciab.prb |= CIAB_PRB_MTR)
303 #define SELECT(mask) (ciab.prb &= ~mask)
304 #define DESELECT(mask) (ciab.prb |= mask)
305 #define SELMASK(drive) (1 << (3 + (drive & 3)))
306
307 /*
308 * Delay for a number of milliseconds
309 * - tried ciab.tod but seems to miss values and screw up
310 * - stupid busy loop for now
311 */
312 static int
313 delay(delay_ms)
314 int delay_ms;
315 {
316 long cnt, inner;
317 int val;
318
319 DELAY (delay_ms * 1000 * 25); /* NOTE: DELAY seems to run too fast */
320 return(val);
321 }
322
323 /*
324 * motor control stuff
325 */
326 void
327 fd_motor_to(fdcu)
328 fdcu_t fdcu;
329 {
330 printf("timeout starting motor\n"); /* XXXX */
331 fdc_data[fdcu].motor_fdu = -2;
332 }
333
334 void
335 fd_motor_on(fdc, fdu)
336 fdc_p fdc;
337 fdu_t fdu;
338 {
339 int i;
340
341 /* deselect all drives */
342 for (i = 0; i < DRVS_PER_CTLR; i++)
343 DESELECT(SELMASK(i));
344
345 /* turn on the unit's motor */
346 MOTOR_ON;
347 SELECT(SELMASK(fdu));
348
349 timeout((timeout_t)fd_motor_to, (caddr_t)fdc->fdcu, hz);
350 while (ciaa.pra & CIAA_PRA_RDY)
351 ;
352 untimeout((timeout_t)fd_motor_to, (caddr_t)fdc->fdcu);
353 fdc->motor_fdu = fdu;
354 }
355
356 void
357 fd_turnoff(fdc)
358 fdc_p fdc;
359 {
360 int i;
361
362 if (fdc->motor_fdu != -1) {
363 /* deselect all drives */
364 for (i = 0; i < DRVS_PER_CTLR; i++)
365 DESELECT(SELMASK(i));
366
367 /* turn off the unit's motor */
368 MOTOR_OFF;
369 SELECT(SELMASK(fdc->motor_fdu));
370 MOTOR_ON;
371 DESELECT(SELMASK(fdc->motor_fdu));
372 }
373
374 fdc->motor_fdu = -1;
375 }
376
377 void
378 fd_turnon(fdc, fdu)
379 fdc_p fdc;
380 fdu_t fdu;
381 {
382 if (fdc->motor_fdu == fdu)
383 return;
384
385 fd_turnoff(fdc);
386 fd_motor_on(fdc, fdu);
387 }
388
389 /*
390 * Step the drive once in its current direction
391 */
392 void
393 fd_step()
394 {
395 ciab.prb &= ~CIAB_PRB_STEP;
396 ciab.prb |= CIAB_PRB_STEP;
397 }
398
399 /*
400 * Select the side to use for a particular drive.
401 * The drive must have been calibrated at some point before this.
402 * The drive must also be active and the motor must be running.
403 */
404 void
405 fd_select_side(fd, side)
406 fd_p fd;
407 int side;
408 {
409 if (fd->side == side)
410 return;
411
412 /* select the requested side */
413 if (side == 0)
414 ciab.prb &= ~CIAB_PRB_SIDE;
415 else
416 ciab.prb |= CIAB_PRB_SIDE;
417 delay(fd->ft->side_time);
418 fd->side = side;
419 }
420
421 /*
422 * Select the direction to use for the current particular drive.
423 */
424 void
425 fd_select_dir(fd, dir)
426 fd_p fd;
427 int dir;
428 {
429 if (fd->dir == dir)
430 return;
431
432 /* select the requested direction */
433 if (dir == 0)
434 ciab.prb &= ~CIAB_PRB_DIR;
435 else
436 ciab.prb |= CIAB_PRB_DIR;
437 delay(fd->ft->settle_time);
438 fd->dir = dir;
439 }
440
441 /*
442 * Seek the drive to track 0.
443 * The drive must be active and the motor must be running.
444 * Returns standard floppy error code. /* XXXX doesn't return anything
445 */
446 void
447 fd_calibrate(fd)
448 fd_p fd;
449 {
450 fd_select_dir(fd, 1);
451
452 /* loop until we hit track 0 */
453 while (ciaa.pra & CIAA_PRA_TK0) {
454 fd_step();
455 delay(4);
456 }
457
458 /* set known values */
459 fd->cyl = 0;
460
461 delay (fd->ft->settle_time);
462 }
463
464 /*
465 * Seek the drive to the requested track.
466 * The drive must be active and the motor must be running.
467 */
468 void
469 fd_seek(fd, track)
470 fd_p fd;
471 int track;
472 {
473 int cyl, side;
474 int dir, cnt;
475
476 cyl = track >> 1;
477 side = (track % 2) ^ 1;
478
479 if (fd->cyl == -1)
480 fd_calibrate(fd);
481
482 fd_select_side(fd, side);
483
484 if (cyl < fd->cyl) {
485 dir = 1;
486 cnt = fd->cyl - cyl;
487 } else {
488 dir = 0;
489 cnt = cyl - fd->cyl;
490 }
491
492 fd_select_dir(fd, dir);
493
494 if (cnt) {
495 while (cnt) {
496 fd_step();
497 delay(fd->ft->step_delay);
498 --cnt;
499 }
500 delay(fd->ft->settle_time);
501 }
502
503 fd->cyl = cyl;
504 }
505
506 void
507 encode(data, dest, csum)
508 u_long data;
509 u_long *dest, *csum;
510 {
511 u_long data2;
512
513 data &= 0x55555555;
514 data2 = data ^ 0x55555555;
515 data |= ((data2 >> 1) | 0x80000000) & (data2 << 1);
516
517 if (*(dest - 1) & 0x00000001)
518 data &= 0x7FFFFFFF;
519
520 *csum ^= data;
521 *dest = data;
522 }
523
524 u_long
525 encode_long(data, dest)
526 u_long data;
527 u_long *dest;
528 {
529 u_long csum;
530
531 csum = 0;
532
533 encode(data >> 1, dest, &csum);
534 encode(data, dest + 1, &csum);
535
536 return(csum & 0x55555555);
537 }
538
539 void
540 encode_block(dest, from, len, csum)
541 u_long *dest, *csum;
542 u_char *from;
543 int len;
544 {
545 int cnt, to_cnt = 0;
546 u_long data, *src;
547
548 to_cnt = 0;
549 src = (u_long *)from;
550
551 /* odd bits */
552 for (cnt = 0; cnt < len / 4; cnt++) {
553 data = src[cnt] >> 1;
554 encode(data, dest + to_cnt++, csum);
555 }
556
557 /* even bits */
558 for (cnt = 0; cnt < len / 4; cnt++) {
559 data = src[cnt];
560 encode(data, dest + to_cnt++, csum);
561 }
562
563 *csum &= 0x55555555;
564 }
565
566 void
567 correct(raw)
568 u_long *raw;
569 {
570 u_char data, *ptr;
571
572 ptr = (u_char *)raw;
573
574 data = *ptr;
575 if (*(ptr - 1) & 0x01) { /* XXXX will choke on old GVP's */
576 *ptr = data & 0x7f;
577 return;
578 }
579
580 if (data & 0x40)
581 return;
582
583 *ptr |= 0x80;
584 }
585
586 /*
587 * amiga_write converts track/labels data to raw track data
588 */
589 void
590 amiga_write(fd)
591 fd_p fd;
592 {
593 u_long *raw, csum, format;
594 u_char *data, *labels;
595 int cnt, track;
596
597 raw = (u_long *)raw_buf; /* XXXX never used while intr? */
598 /* XXXX never waits after here? */
599 data = fd->buf_data;
600 labels = fd->buf_labels;
601 track = fd->buf_track;
602
603 /* gap space */
604 for (cnt = fd->ft->gap_size; cnt; cnt--)
605 *raw++ = 0xaaaaaaaa;
606
607 /* sectors */
608 for (cnt = 0; cnt < fd->sects; cnt++) {
609 *raw = 0xaaaaaaaa;
610 correct(raw);
611 ++raw;
612
613 *raw++ = 0x44894489;
614
615 format = 0xff000000 | (track << 16) | (cnt << 8) | (fd->sects - cnt);
616 csum = encode_long(format,raw);
617 raw += 2;
618
619 encode_block(raw, labels + cnt * 16, 16, &csum);
620 raw += 8;
621 csum = encode_long(csum, raw);
622 raw += 2;
623
624 csum = 0;
625 encode_block(raw+2, data + cnt * 512, 512, &csum);
626 csum = encode_long(csum, raw);
627 correct (raw+2);
628 raw += 256 + 2;
629 }
630 *raw = 0xaaa80000;
631 correct(raw);
632
633 }
634
635 #define get_word(raw) (*(u_short *)(raw))
636 #define get_long(raw) (*(u_long *)(raw))
637
638 #define decode_long(raw) \
639 (((get_long(raw) & 0x55555555) << 1) | \
640 (get_long((raw)+4) & 0x55555555))
641
642 #define MFM_NOSYNC 1
643 #define MFM_HEADER 2
644 #define MFM_DATA 3
645 #define MFM_TRACK 4
646
647 /*
648 * scan_sync - looks for the next start of sector marked by a sync. When
649 * sect != 0, can't be certain of a starting sync.
650 */
651 u_long
652 scan_sync(raw, end, sect)
653 u_long raw, end;
654 int sect;
655 {
656 u_short data;
657
658 if (sect == 0) {
659 while (raw < end) {
660 data = get_word(raw);
661 if (data == 0x4489)
662 break;
663 raw += 2;
664 }
665 if (raw > end)
666 return(0);
667 }
668
669 while (raw < end) {
670 data = get_word(raw);
671 if (data != 0x4489)
672 break;
673 raw += 2;
674 }
675 if (raw > end)
676 return(0);
677 return(raw);
678 }
679
680 /*
681 * amiga_read reads a raw track of data into a track buffer
682 */
683 int
684 amiga_read(fd)
685 fd_p fd;
686 {
687 u_char *track_data, *label_data;
688 u_long raw, end, val1, val2, csum, data_csum;
689 u_long *data, *labels;
690 int scnt, cnt, format, tnum, sect, snext;
691
692 track_data = fd->buf_data;
693 label_data = fd->buf_labels;
694 raw = (u_long)raw_buf; /* XXXX see above about glb */
695
696 end = raw + fd->ft->read_size;
697
698 for (scnt = fd->sects-1; scnt >= 0; scnt--) {
699 if ((raw = scan_sync(raw, end, scnt == fd->sects-1)) == 0) {
700 /* XXXX */
701 printf("can't find sync for sector %d\n", scnt);
702 return(1);
703 }
704
705 val1 = decode_long(raw);
706
707 format = (val1 >> 24) & 0xFF;
708 tnum = (val1 >> 16) & 0xFF;
709 sect = (val1 >> 8) & 0xFF;
710 snext = (val1) & 0xFF;
711
712 labels = (u_long *)(label_data + (sect << 4));
713
714 csum = 0;
715 val1 = get_long(raw);
716 raw += 4;
717 csum ^= val1;
718 val1 = get_long(raw);
719 raw += 4;
720 csum ^= val1;
721
722 for (cnt = 0; cnt < 4; cnt++) {
723 val1 = get_long(raw+16);
724 csum ^= val1;
725 val1 &= 0x55555555;
726 val2 = get_long(raw);
727 raw += 4;
728 csum ^= val2;
729 val2 &= 0x55555555;
730 val2 = val2 << 1;
731 val1 |= val2;
732 *labels++ = val1;
733 }
734
735 csum &= 0x55555555;
736 raw += 16;
737 val1 = decode_long(raw);
738 raw += 8;
739 if (val1 != csum) {
740 /* XXXX */
741 printf("MFM_HEADER %d: %08x,%08x\n", scnt,
742 val1, csum);
743 return(MFM_HEADER);
744 }
745
746 /* verify track */
747 if (tnum != fd->buf_track) {
748 /* XXXX */
749 printf("MFM_TRACK %d: %d, %d\n", scnt, tnum,
750 fd->buf_track);
751 return(MFM_TRACK);
752 }
753
754 data_csum = decode_long(raw);
755 raw += 8;
756 data = (u_long *)(track_data + (sect << 9));
757
758 csum = 0;
759 for (cnt = 0; cnt < 128; cnt++) {
760 val1 = get_long(raw + 512);
761 csum ^= val1;
762 val1 &= 0x55555555;
763 val2 = get_long(raw);
764 raw += 4;
765 csum ^= val2;
766 val2 &= 0x55555555;
767 val2 = val2 << 1;
768 val1 |= val2;
769 *data++ = val1;
770 }
771
772 csum &= 0x55555555;
773 raw += 512;
774
775 if (data_csum != csum) {
776 printf(
777 "MFM_DATA: f=%d t=%d s=%d sn=%d sc=%d %lx, %lx\n",
778 format, tnum, sect, snext, scnt, data_csum, csum);
779 return(MFM_DATA);
780 }
781 }
782 return(0);
783 }
784
785 /*
786 * Return unit ID number of given disk
787 * XXXX This function doesn't return anything.
788 */
789 u_long
790 loop_read_id(unit)
791 int unit;
792 {
793 u_long id;
794 u_long id_bit;
795
796 id = 0;
797
798 /* loop and read disk ID */
799 for (id_bit = 0x80000000; id_bit; id_bit >>= 1) {
800 SELECT(SELMASK(unit));
801
802 /* read and store value of DSKRDY */
803 if (ciaa.pra & CIAA_PRA_RDY)
804 id |= id_bit;
805
806 DESELECT(SELMASK(unit));
807 }
808 }
809
810 u_long
811 get_drive_id(unit)
812 int unit;
813 {
814 int t;
815 u_long id, id_bit;
816 u_char mask1, mask2;
817 volatile u_char *a_ptr;
818 volatile u_char *b_ptr;
819
820 id = 0;
821 a_ptr = &ciaa.pra;
822 b_ptr = &ciab.prb;
823 mask1 = ~(1 << (3 + unit));
824 mask2 = 1 << (3 + unit);
825
826 *b_ptr &= ~CIAB_PRB_MTR;
827 *b_ptr &= mask1;
828 *b_ptr |= mask2;
829 *b_ptr |= CIAB_PRB_MTR;
830 *b_ptr &= mask1;
831 *b_ptr |= mask2;
832
833 for (id_bit = 0x80000000; id_bit; id_bit >>= 1) {
834 *b_ptr &= mask1;
835 if ((*a_ptr) & CIAA_PRA_RDY)
836 id |= id_bit;
837 *b_ptr |= mask2;
838 }
839
840 /* all amigas have internal drives at 0. */
841 if (unit == 0 && id == FD_NONE)
842 return(FD_DD_3);
843 return(id);
844 #if 0
845 /* set up for ID */
846 MOTOR_ON;
847 SELECT(SELMASK(unit));
848 DESELECT(SELMASK(unit));
849 MOTOR_OFF;
850 SELECT(SELMASK(unit));
851 DESELECT(SELMASK(unit));
852
853 return loop_read_id(unit); /* XXXX gotta fix loop_read_id() if use */
854 #endif
855 }
856
857 int
858 get_drive_type(u_long id)
859 {
860 int type;
861
862 for (type = 0; type < num_dr_types; type++)
863 if (drive_types[type].id == id)
864 return(type);
865 return(-1);
866 }
867
868 void
869 fd_probe(fd)
870 fd_p fd;
871 {
872 u_long id;
873 int type, data;
874
875 fd->ft = NULL;
876
877 id = get_drive_id(fd->fdu);
878 type = get_drive_type(id);
879
880 /* get_drive_id shuts off the motor */
881 /* XXXX fdc_data[0] only as long as there is one controller */
882 if (fd->fdu == fdc_data[0].motor_fdu)
883 fdc_data[0].motor_fdu = -1;
884
885 if (type == -1) {
886 /* XXXX */
887 printf("fd_probe: unsupported drive type %08x found\n", id);
888 return;
889 }
890
891 fd->type = type;
892 fd->ft = &drive_types[type];
893 if (fd->ft->tracks == 0) {
894 /* XXXX */
895 printf("no drive type %d\n", type);
896 }
897 fd->side = -1;
898 fd->dir = -1;
899 fd->cyl = -1;
900
901 fd->sects = 11 * drive_types[type].sect_mult;
902 fd->size = fd->sects *
903 drive_types[type].tracks *
904 drive_types[type].heads;
905 fd->flags = 0;
906 }
907
908 void
909 track_read(fdc, fd, track)
910 fdc_p fdc;
911 fd_p fd;
912 int track;
913 {
914 u_long len;
915
916 fd->buf_track = track;
917 fdc->state = WAIT_READ;
918
919 fd_seek(fd, track);
920
921 len = fd->ft->read_size >> 1;
922
923 /* setup adkcon bits correctly */
924 custom.adkcon = ADKF_MSBSYNC;
925 custom.adkcon = ADKF_SETCLR | ADKF_WORDSYNC | ADKF_FAST;
926
927 custom.dsksync = MFM_SYNC;
928
929 custom.dsklen = 0;
930 delay(fd->ft->side_time);
931 timeout((timeout_t)fd_timeout, (caddr_t)fdc, 2 * hz);
932
933 custom.dskpt = (u_char *)kvtop(raw_buf);
934 custom.dsklen = len | DSKLEN_DMAEN;
935 custom.dsklen = len | DSKLEN_DMAEN;
936 }
937
938 void
939 track_write(fdc, fd)
940 fdc_p fdc;
941 fd_p fd;
942 {
943 int track;
944 u_long len;
945 u_short adk;
946
947 amiga_write(fd);
948
949 track = fd->buf_track;
950 fd->write_cnt += 1;
951
952 fdc->saved = fdc->state;
953 fdc->state = WAIT_WRITE;
954
955 fd_seek(fd, track);
956
957 len = fd->ft->write_size >> 1;
958
959 if ((ciaa.pra & CIAA_PRA_WPRO) == 0)
960 return;
961
962 /* clear adkcon bits */
963 custom.adkcon = ADKF_PRECOMP1 | ADKF_PRECOMP0 | ADKF_WORDSYNC |
964 ADKF_MSBSYNC;
965
966 /* set appropriate adkcon bits */
967 adk = ADKF_SETCLR | ADKF_FAST | ADKF_MFMPREC;
968 if (track >= fd->ft->precomp2)
969 adk |= ADKF_PRECOMP1;
970 else if (track >= fd->ft->precomp1)
971 adk |= ADKF_PRECOMP0;
972 custom.adkcon = adk;
973
974 custom.dsklen = DSKLEN_WRITE;
975 delay(fd->ft->side_time);
976 timeout((timeout_t)fd_timeout, (caddr_t)fdc, 2 * hz);
977
978 custom.dskpt = (u_char *)kvtop(raw_buf); /* XXXX again raw */
979 custom.dsklen = len | DSKLEN_DMAEN | DSKLEN_WRITE;
980 custom.dsklen = len | DSKLEN_DMAEN | DSKLEN_WRITE;
981 }
982
983 /*
984 * Floppy Device Code
985 */
986 int
987 fdattach(ad)
988 struct amiga_device *ad;
989 {
990 int fdcu = 0;
991 fdc_p fdc = fdc_data + fdcu;
992 int i;
993 unsigned long id;
994 int type;
995
996 fdc->fdcu = fdcu;
997 fdc->state = FINDWORK;
998 fdc->fd = NULL;
999 fdc->motor_fdu = -1;
1000
1001 for (i = 0; i < DRVS_PER_CTLR; i++) {
1002 fdc->fd_data[i].fdu = i;
1003 fdc->fd_data[i].flags = 0;
1004
1005 fdc->fd_data[i].buf_track = -1;
1006 fdc->fd_data[i].buf_dirty = 0;
1007 fdc->fd_data[i].buf_data =
1008 malloc(MAX_SECTS * 512, M_DEVBUF, 0);
1009 fdc->fd_data[i].buf_labels =
1010 malloc(MAX_SECTS * 16, M_DEVBUF, 0);
1011
1012 if (fdc->fd_data[i].buf_data == NULL ||
1013 fdc->fd_data[i].buf_labels == NULL) {
1014 printf("Cannot alloc buffer memory for fd device\n");
1015 return(0);
1016 }
1017
1018 id = get_drive_id(i);
1019 type = get_drive_type(id);
1020
1021 if (type != -1 && drive_types[type].tracks != 0) {
1022 printf("floppy drive %d: %s\n", i,
1023 drive_types[type].name);
1024 }
1025 }
1026
1027 raw_buf = (char *)alloc_chipmem(30000);
1028 if (raw_buf == NULL) {
1029 printf("Cannot alloc chipmem for fd device\n");
1030 return 0;
1031 }
1032
1033 /* enable disk DMA */
1034 custom.dmacon = DMAF_SETCLR | DMAF_DISK;
1035
1036 /* enable interrupts for IRQ_DSKBLK */
1037 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_FLG;
1038 custom.intena = INTF_SETCLR | INTF_SOFTINT;
1039
1040 /* enable disk block interrupts */
1041 custom.intena = INTF_SETCLR | INTF_DSKBLK;
1042
1043 return(1);
1044 }
1045
1046 int
1047 Fdopen(dev, flags)
1048 dev_t dev;
1049 int flags;
1050 {
1051 fdcu_t fdcu;
1052 fdc_p fdc;
1053 fdu_t fdu;
1054 fd_p fd;
1055
1056 fdcu = 0;
1057 fdc = fdc_data + fdcu;
1058 fdu = UNIT(dev);
1059 fd = fdc->fd_data + fdu;
1060
1061 /* check bounds */
1062 if (fdu >= DRVS_PER_CTLR)
1063 return(ENXIO);
1064
1065 /*
1066 * XXXX don't probe if device is currently selected
1067 * it may be in the middle of a DMA transfer and fd_probe
1068 * will deselect all drives
1069 */
1070 if (fdc->motor_fdu < 0)
1071 fd_probe(fd);
1072 #if 0
1073 else
1074 printf ("fd: Fdopen called with a drive selected\n");
1075 #endif
1076
1077
1078 if (fd->ft == NULL || fd->ft->tracks == 0)
1079 return(ENXIO);
1080
1081 fd->flags |= FDF_OPEN;
1082 fd->write_cnt = 0;
1083
1084 return(0);
1085 }
1086
1087 int
1088 fdclose(dev, flags)
1089 dev_t dev;
1090 int flags;
1091 {
1092 struct buf *dp,*bp;
1093 fdcu_t fdcu;
1094 fdc_p fdc;
1095 fdu_t fdu;
1096 fd_p fd;
1097
1098 fdcu = 0;
1099 fdc = fdc_data + fdcu;
1100 fdu = UNIT(dev);
1101 fd = fdc->fd_data + fdu;
1102
1103
1104 /* wait until activity is done for this drive */
1105 /* XXXX ACK! sleep.. */
1106 do {
1107 dp = &(fd->head);
1108 bp = dp->b_actf;
1109 } while (bp);
1110
1111 /* XXXX */
1112 printf("wrote %d tracks (%d)\n", fd->write_cnt, fd->buf_dirty);
1113
1114 fd->buf_track = -1;
1115 fd->buf_dirty = 0;
1116 fd->flags &= ~FDF_OPEN;
1117
1118 return(0);
1119 }
1120
1121 int
1122 fdioctl(dev, cmd, data, flag, p)
1123 dev_t dev;
1124 int cmd, flag;
1125 caddr_t data;
1126 struct proc *p;
1127 {
1128 struct disklabel *fd_label;
1129 fdcu_t fdcu;
1130 fdc_p fdc;
1131 fdu_t fdu;
1132 fd_p fd;
1133 int error;
1134
1135 fdcu = 0;
1136 fdc = fdc_data + fdcu;
1137 fdu = UNIT(dev);
1138 fd = fdc->fd_data + fdu;
1139 error = 0;
1140
1141 if (cmd != DIOCGDINFO)
1142 return (EINVAL);
1143
1144 fd_label = (struct disklabel *)data;
1145
1146 bzero(fd_label, sizeof(fd_label));
1147 fd_label->d_magic = DISKMAGIC;
1148 fd_label->d_type = DTYPE_FLOPPY;
1149 strncpy(fd_label->d_typename, "fd", sizeof(fd_label->d_typename) - 1);
1150 strcpy(fd_label->d_packname, fd->ft->name);
1151
1152 fd_label->d_rpm = 300 / fd->ft->sect_mult;
1153 fd_label->d_secsize = 512;
1154 fd_label->d_nsectors = fd->sects;
1155 fd_label->d_ntracks = fd->ft->heads;
1156 fd_label->d_ncylinders = fd->ft->tracks;
1157 fd_label->d_secpercyl = fd_label->d_nsectors * fd_label->d_ntracks;
1158 fd_label->d_secperunit= fd_label->d_ncylinders * fd_label->d_secpercyl;
1159
1160 fd_label->d_magic2 = DISKMAGIC;
1161 fd_label->d_partitions[0].p_offset = 0;
1162 fd_label->d_partitions[0].p_size = fd_label->d_secperunit;
1163 fd_label->d_partitions[0].p_fstype = FS_UNUSED;
1164 fd_label->d_npartitions = 1;
1165
1166 fd_label->d_checksum = 0;
1167 fd_label->d_checksum = dkcksum(fd_label);
1168
1169 return(0);
1170 }
1171
1172 int
1173 fdsize(dev)
1174 dev_t dev;
1175 {
1176 /* check UNIT? */
1177 return((fdc_data + 0)->fd_data[UNIT(dev)].size);
1178 }
1179
1180 void
1181 fdstrategy(bp)
1182 struct buf *bp;
1183 {
1184 fdcu_t fdcu;
1185 fdc_p fdc;
1186 fdu_t fdu;
1187 fd_p fd;
1188 long nblocks, blknum;
1189 struct buf *dp;
1190 int s;
1191
1192 fdcu = 0;
1193 fdc = fdc_data + fdcu;
1194 fdu = UNIT(bp->b_dev);
1195 fd = fdc->fd_data + fdu;
1196
1197 if (bp->b_blkno < 0) {
1198 /* XXXX */
1199 printf("fdstrat error: fdu = %d, blkno = %d, bcount = %d\n",
1200 fdu, bp->b_blkno, bp->b_bcount);
1201 bp->b_error = EINVAL;
1202 bp->b_flags |= B_ERROR;
1203 biodone(bp);
1204 return;
1205 }
1206
1207 /*
1208 * Set up block calculations.
1209 */
1210 blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / FDBLK;
1211 nblocks = fd->sects * fd->ft->tracks * fd->ft->heads;
1212 if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
1213 nblocks -= blknum;
1214 if (nblocks == 0) {
1215 bp->b_resid = bp->b_bcount;
1216 goto done;
1217 }
1218 if (nblocks < 0) {
1219 bp->b_error = EINVAL;
1220 bp->b_flags |= B_ERROR;
1221 done:
1222 biodone(bp);
1223 return;
1224 }
1225 bp->b_bcount = dbtob(nblocks);
1226 }
1227
1228 bp->b_cylin = blknum; /* set here for disksort */
1229 dp = &(fd->head);
1230
1231 s = splbio();
1232 disksort(dp, bp);
1233 untimeout((timeout_t)fd_turnoff, (caddr_t)fdc); /* a good idea */
1234 fdstart(fdc);
1235 splx(s);
1236 }
1237
1238 /*
1239 * We have just queued something.. if the controller is not busy
1240 * then simulate the case where it has just finished a command
1241 * So that it (the interrupt routine) looks on the queue for more
1242 * work to do and picks up what we just added.
1243 * If the controller is already busy, we need do nothing, as it
1244 * will pick up our work when the present work completes
1245 */
1246 void
1247 fdstart(fdc)
1248 fdc_p fdc;
1249 {
1250 int s;
1251
1252 s = splbio();
1253 if (fdc->state == FINDWORK)
1254 fdintr(fdc->fdcu);
1255 splx(s);
1256 }
1257
1258 /*
1259 * just ensure it has the right spl
1260 */
1261 void
1262 fd_pseudointr(fdc)
1263 fdc_p fdc;
1264 {
1265 int s;
1266
1267 s = splbio();
1268 fdintr(fdc->fdcu);
1269 splx(s);
1270 }
1271
1272 void
1273 fd_timeout(fdc)
1274 fdc_p fdc;
1275 {
1276 struct buf *dp,*bp;
1277 fd_p fd;
1278
1279 fd = fdc->fd;
1280 dp = &fd->head;
1281 bp = dp->b_actf;
1282
1283 if (fd == NULL) {
1284 printf ("fd_timeout called with no active drive?\n");
1285 return;
1286 }
1287
1288 /* XXXX */
1289 printf("fd%d: Operation timeout; state %d\n", fd->fdu, fdc->state);
1290 if (bp) {
1291 retrier(fdc);
1292 #if 0 /* XXX retrier already set fdc->state? */
1293 fdc->state = DONE_IO;
1294 #endif
1295 if (fdc->retry < 6)
1296 fdc->retry = 6;
1297 } else {
1298 fdc->fd = NULL;
1299 fdc->state = FINDWORK;
1300 }
1301
1302 fd_pseudointr(fdc);
1303 }
1304
1305 /*
1306 * keep calling the state machine until it returns a 0
1307 * ALWAYS called at SPLBIO
1308 */
1309 void
1310 fdintr(fdcu)
1311 fdcu_t fdcu;
1312 {
1313 fdc_p fdc;
1314
1315 fdc = fdc_data + fdcu;
1316 while (fdstate(fdc))
1317 ;
1318 }
1319
1320 /*
1321 * The controller state machine.
1322 * if it returns a non zero value, it should be called again immediatly
1323 */
1324 int
1325 fdstate(fdc)
1326 fdc_p fdc;
1327 {
1328 struct buf *dp,*bp;
1329 int track, read, sec, i;
1330 u_long blknum;
1331 fd_p fd;
1332
1333 fd = fdc->fd;
1334
1335 if (fd == NULL) {
1336 /* search for a unit do work with */
1337 for (i = 0; i < DRVS_PER_CTLR; i++) {
1338 fd = fdc->fd_data + i;
1339 dp = &(fd->head);
1340 bp = dp->b_actf;
1341 if (bp) {
1342 fdc->fd = fd;
1343 break;
1344 }
1345 }
1346
1347 if (fdc->fd)
1348 return(1);
1349
1350 fdc->state = FINDWORK;
1351 TRACE1("[fdc%d IDLE]\n", fdc->fdcu);
1352 return(0);
1353 }
1354
1355 dp = &(fd->head);
1356 bp = dp->b_actf;
1357
1358 blknum = (u_long)bp->b_blkno * DEV_BSIZE / FDBLK + fd->skip / FDBLK;
1359 track = blknum / fd->sects;
1360 sec = blknum % fd->sects;
1361
1362 read = bp->b_flags & B_READ;
1363 TRACE1("fd%d", fd->fdu);
1364 TRACE1("[%s]", fdstates[fdc->state]);
1365 TRACE1("(0x%x) ", fd->flags);
1366 TRACE1("%d\n", fd->buf_track);
1367
1368 untimeout((timeout_t)fd_turnoff, (caddr_t)fdc);
1369 timeout((timeout_t)fd_turnoff, (caddr_t)fdc, 4 * hz);
1370
1371 switch (fdc->state) {
1372 case FINDWORK:
1373 if (!bp) {
1374 if (fd->buf_dirty) {
1375 track_write(fdc, fd);
1376 return(0);
1377 }
1378 fdc->fd = NULL;
1379 return(1);
1380 }
1381
1382 fdc->state = DOSEEK;
1383 fdc->retry = 0;
1384 fd->skip = 0;
1385 return(1);
1386 case DOSEEK:
1387 fd_turnon(fdc, fd->fdu);
1388
1389 /*
1390 * If not started, error starting it
1391 */
1392 if (fdc->motor_fdu != fd->fdu) {
1393 /* XXXX */
1394 printf("motor not on!\n");
1395 }
1396
1397 /*
1398 * If track not in buffer, read it in
1399 */
1400 if (fd->buf_track != track) {
1401 TRACE1("do track %d\n", track);
1402
1403 if (fd->buf_dirty) {
1404 track_write(fdc, fd);
1405 return (0);
1406 } else {
1407 if (read || sec != 0 ||
1408 ((bp->b_bcount - fd->skip)/FDBLK) % fd->sects) {
1409 track_read(fdc, fd, track);
1410 return(0);
1411 }
1412 /*
1413 * if writing a full track, don't bother reading
1414 * in the old track - we're just going to overwrite
1415 * it all anyway.
1416 */
1417 fd_seek (fd, track);
1418 fd->buf_track = track;
1419 /* clear sector labels */
1420 bzero(fd->buf_labels, MAX_SECTS * 16);
1421 }
1422 }
1423
1424 fdc->state = DO_IO;
1425 return(1);
1426 case DO_IO:
1427 if (read)
1428 bcopy(&fd->buf_data[sec * FDBLK],
1429 bp->b_un.b_addr + fd->skip, FDBLK);
1430 else {
1431 bcopy(bp->b_un.b_addr + fd->skip,
1432 &fd->buf_data[sec * FDBLK], FDBLK);
1433 fd->buf_dirty = 1;
1434 if (IMMED_WRITE) {
1435 fdc->state = DONE_IO;
1436 track_write(fdc, fd);
1437 return(0);
1438 }
1439 }
1440 case DONE_IO:
1441 fd->skip += FDBLK;
1442 if (fd->skip < bp->b_bcount)
1443 fdc->state = DOSEEK;
1444 else {
1445 fd->skip = 0;
1446 if (bp == NULL)
1447 printf ("fd: fdstate DONE_IO bp == NULL\n");
1448 else {
1449 bp->b_resid = 0;
1450 dp->b_actf = bp->b_actf;
1451 biodone(bp);
1452 }
1453 fdc->state = FINDWORK;
1454 }
1455 return(1);
1456 case WAIT_READ:
1457 untimeout((timeout_t)fd_timeout, (caddr_t)fdc);
1458 custom.dsklen = 0;
1459 if (amiga_read(fd) == 0) {
1460 fdc->retry = 0;
1461 fdc->state = DO_IO;
1462 return(1);
1463 }
1464 if (fdc->retry++ < 6) {
1465 track_read(fdc, fd, track);
1466 return(0);
1467 }
1468 if (bp) {
1469 bp->b_flags |= B_ERROR;
1470 bp->b_error = EIO;
1471 bp->b_resid = bp->b_bcount - fd->skip;
1472 dp->b_actf = bp->b_actf;
1473 fd->skip = 0;
1474 biodone(bp);
1475 }
1476 fdc->state = FINDWORK;
1477 return (1);
1478 case WAIT_WRITE:
1479 untimeout((timeout_t)fd_timeout, (caddr_t)fdc);
1480 custom.dsklen = 0;
1481 fdc->state = fdc->saved;
1482 fd->buf_dirty = 0;
1483 /*
1484 * post-write delay - should delay only if changing sides
1485 * after a write?
1486 */
1487 delay (4);
1488 return(1);
1489 default:
1490 /* XXXX */
1491 printf("Unexpected FD int->%d\n", fdc->state);
1492 return 0;
1493 }
1494
1495 /* Come back immediatly to new state */
1496 return(1);
1497 }
1498
1499 int
1500 retrier(fdc)
1501 fdc_p fdc;
1502 {
1503 struct buf *dp,*bp;
1504 fd_p fd;
1505
1506 fd = fdc->fd;
1507 dp = &(fd->head);
1508 bp = dp->b_actf;
1509
1510 #if 0
1511 switch(fdc->retry) {
1512 case 0:
1513 case 1:
1514 case 2:
1515 fdc->state = SEEKCOMPLETE;
1516 break;
1517 case 3:
1518 case 4:
1519 case 5:
1520 fdc->state = STARTRECAL;
1521 break;
1522 case 6:
1523 fdc->state = RESETCTLR;
1524 break;
1525 case 7:
1526 break;
1527 default:
1528 #endif
1529 /* XXXX */
1530 printf("fd%d: hard error\n", fd->fdu);
1531
1532 if (bp == NULL)
1533 printf ("fd: retrier bp == NULL\n");
1534 else {
1535 bp->b_flags |= B_ERROR;
1536 bp->b_error = EIO;
1537 bp->b_resid = bp->b_bcount - fd->skip;
1538 dp->b_actf = bp->b_actf;
1539 fd->skip = 0;
1540 biodone(bp);
1541 }
1542 fdc->state = FINDWORK;
1543 return(1);
1544 #if 0
1545 fdc->retry++;
1546 return(1);
1547 #endif
1548 }
1549
1550 #endif
1551