fd.c revision 1.3 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.3 1994/04/07 17:43:29 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 0x00000000
113 #define FD_DD_3 0xffffffff /* double-density 3.5" (880K) */
114 #define FD_HD_3 0x55555555 /* high-density 3.5" (1760K) */
115
116 struct fd_type {
117 int id;
118 char *name;
119 int tracks;
120 int heads;
121 int read_size;
122 int write_size;
123 int sect_mult;
124 int precomp1;
125 int precomp2;
126 int step_delay;
127 int side_time;
128 int settle_time;
129 };
130
131 struct fd_type drive_types[] = {
132 /* id name tr he rdsz wrsz sm pc1 pc2 sd st st */
133 { FD_DD_3, "DD 3.5", 80, 2, 14716, 13630, 1, 80, 161, 3, 18, 1 },
134 { FD_HD_3, "HD 3.5", 80, 2, 29432, 27260, 2, 80, 161, 3, 18, 1 },
135 { FD_NONE, "No Drive", 0, }
136 };
137 int num_dr_types = sizeof(drive_types) / sizeof(drive_types[0]);
138
139 /*
140 * Per drive structure.
141 * N per controller (presently 4) (DRVS_PER_CTLR)
142 */
143 #define DRVS_PER_CTLR 4
144 struct fd_data {
145 int fdu; /* This unit number */
146 struct buf head; /* Head of buf chain */
147 struct buf rhead; /* Raw head of buf chain */
148 int type; /* Drive type */
149 struct fd_type *ft; /* Pointer to type descriptor */
150 int flags;
151 #define FDF_OPEN 0x01 /* it's open */
152 int skip;
153 int sects; /* number of sectors in a track */
154 int size; /* size of disk in sectors */
155 int side; /* current side disk is on */
156 int dir; /* current direction of stepping */
157 int cyl; /* current cylinder disk is on */
158 int buf_track;
159 int buf_dirty;
160 char *buf_data;
161 char *buf_labels;
162 int write_cnt;
163 };
164
165 /*
166 * Per controller structure.
167 */
168 struct fdc_data
169 {
170 int fdcu; /* our unit number */
171 struct fd_data *fd; /* drive we are currently doing work for */
172 int motor_fdu; /* drive that has its motor on */
173 int state;
174 int saved;
175 int retry;
176 struct fd_data fd_data[DRVS_PER_CTLR];
177 };
178 struct fdc_data fdc_data[NFD];
179
180 /*
181 * Throughout this file the following conventions will be used:
182 *
183 * fd is a pointer to the fd_data struct for the drive in question
184 * fdc is a pointer to the fdc_data struct for the controller
185 * fdu is the floppy drive unit number
186 * fdcu is the floppy controller unit number
187 * fdsu is the floppy drive unit number on that controller. (sub-unit)
188 */
189 typedef int fdu_t;
190 typedef int fdcu_t;
191 typedef int fdsu_t;
192 typedef struct fd_data *fd_p;
193 typedef struct fdc_data *fdc_p;
194
195 /*
196 * protos.
197 */
198 static int delay __P((int));
199 void encode __P((u_long, u_long *, u_long *));
200 void fd_step __P((void));
201 void fd_seek __P((fd_p, int));
202 void correct __P((u_long *));
203 void fd_probe __P((fd_p));
204 void fd_turnon __P((fdc_p, fdu_t));
205 void fd_turnoff __P((fdc_p));
206 void track_read __P((fdc_p, fd_p, int));
207 void fd_timeout __P((fdc_p));
208 void fd_motor_to __P((fdcu_t));
209 void fd_motor_on __P((fdc_p, fdu_t));
210 void track_write __P((fdc_p, fd_p));
211 void amiga_write __P((fd_p));
212 void fd_calibrate __P((fd_p));
213 void encode_block __P((u_long *, u_char *, int, u_long *));
214 void fd_select_dir __P((fd_p, int));
215 void fd_pseudointr __P((fdc_p));
216 void fd_select_side __P((fd_p, int));
217
218 u_long scan_sync __P((u_long, u_long, int));
219 u_long encode_long __P((u_long, u_long *));
220 u_long loop_read_id __P((int));
221 u_long get_drive_id __P((int));
222
223 int fdstate __P((fdc_p));
224 int retrier __P((fdc_p));
225 int amiga_read __P((fd_p));
226 int get_drive_type __P((u_long));
227
228 /* device routines */
229 int Fdopen __P((dev_t, int));
230 int fdsize __P((dev_t));
231 int fdioctl __P((dev_t, int, caddr_t, int, struct proc *));
232 int fdclose __P((dev_t, int));
233 int fdattach __P((struct amiga_device *));
234
235 void fdintr __P((fdcu_t));
236 void fdstart __P((fdc_p));
237 void fdstrategy __P((struct buf *bp));
238
239 #define DEVIDLE 0
240 #define FINDWORK 1
241 #define DOSEEK 2
242 #define DO_IO 3
243 #define DONE_IO 4
244 #define WAIT_READ 5
245 #define WAIT_WRITE 6
246 #define DELAY_WRITE 7
247 #define RECALCOMPLETE 8
248 #define STARTRECAL 9
249 #define RESETCTLR 10
250 #define SEEKWAIT 11
251 #define RECALWAIT 12
252 #define MOTORWAIT 13
253
254 #undef DEBUG
255
256 #ifdef DEBUG
257
258 char *fdstates[] =
259 {
260 "DEVIDLE",
261 "FINDWORK",
262 "DOSEEK",
263 "DO_IO",
264 "DONE_IO",
265 "WAIT_READ",
266 "WAIT_WRITE",
267 "DELAY_WRITE",
268 "RECALCOMPLETE",
269 "STARTRECAL",
270 "RESETCTLR",
271 "SEEKWAIT",
272 "RECALWAIT",
273 "MOTORWAIT",
274 };
275
276 #define TRACE0(arg) if (fd_debug == 1) printf(arg)
277 #define TRACE1(arg1,arg2) if (fd_debug == 1) printf(arg1,arg2)
278
279 #else /* !DEBUG */
280
281 #define TRACE0(arg)
282 #define TRACE1(arg1,arg2)
283
284 #endif /* !DEBUG */
285
286 extern int hz;
287
288 unsigned char *raw_buf = NULL;
289 #ifdef DEBUG
290 int fd_debug = 1;
291 #else
292 int fd_debug = 0;
293 #endif
294
295 /*
296 * Floppy Support Routines
297 */
298 #define MOTOR_ON (ciab.prb &= ~CIAB_PRB_MTR)
299 #define MOTOR_OFF (ciab.prb |= CIAB_PRB_MTR)
300 #define SELECT(mask) (ciab.prb &= ~mask)
301 #define DESELECT(mask) (ciab.prb |= mask)
302 #define SELMASK(drive) (1 << (3 + (drive & 3)))
303
304 /*
305 * Delay for a number of milliseconds
306 * - tried ciab.tod but seems to miss values and screw up
307 * - stupid busy loop for now
308 */
309 static int
310 delay(delay_ms)
311 int delay_ms;
312 {
313 long cnt, inner;
314 int val;
315
316 for (cnt = 0; cnt < delay_ms; cnt++)
317 for (inner = 0; inner < 500; inner++)
318 val += inner * cnt;
319 return(val);
320 }
321
322 /*
323 * motor control stuff
324 */
325 void
326 fd_motor_to(fdcu)
327 fdcu_t fdcu;
328 {
329 printf("timeout starting motor\n"); /* XXXX */
330 fdc_data[fdcu].motor_fdu = -2;
331 }
332
333 void
334 fd_motor_on(fdc, fdu)
335 fdc_p fdc;
336 fdu_t fdu;
337 {
338 int i;
339 int cnt; /* XXXX not used? */
340
341 cnt = 0; /* XXXX not used? */
342
343 /* deselect all drives */
344 for (i = 0; i < DRVS_PER_CTLR; i++)
345 DESELECT(SELMASK(i));
346
347 /* turn on the unit's motor */
348 MOTOR_ON;
349 SELECT(SELMASK(fdu));
350
351 timeout((timeout_t)fd_motor_to, (caddr_t)fdc->fdcu, hz);
352 while (ciaa.pra & CIAA_PRA_RDY)
353 ;
354 untimeout((timeout_t)fd_motor_to, (caddr_t)fdc->fdcu);
355 fdc->motor_fdu = fdu;
356 }
357
358 void
359 fd_turnoff(fdc)
360 fdc_p fdc;
361 {
362 int i;
363
364 if (fdc->motor_fdu != -1) {
365 /* deselect all drives */
366 for (i = 0; i < DRVS_PER_CTLR; i++)
367 DESELECT(SELMASK(i));
368
369 /* turn off the unit's motor */
370 MOTOR_OFF;
371 SELECT(SELMASK(fdc->motor_fdu));
372 MOTOR_ON;
373 DESELECT(SELMASK(fdc->motor_fdu));
374 }
375
376 fdc->motor_fdu = -1;
377 }
378
379 void
380 fd_turnon(fdc, fdu)
381 fdc_p fdc;
382 fdu_t fdu;
383 {
384 if (fdc->motor_fdu == fdu)
385 return;
386
387 fd_turnoff(fdc);
388 fd_motor_on(fdc, fdu);
389 }
390
391 /*
392 * Step the drive once in its current direction
393 */
394 void
395 fd_step()
396 {
397 ciab.prb &= ~CIAB_PRB_STEP;
398 ciab.prb |= CIAB_PRB_STEP;
399 }
400
401 /*
402 * Select the side to use for a particular drive.
403 * The drive must have been calibrated at some point before this.
404 * The drive must also be active and the motor must be running.
405 */
406 void
407 fd_select_side(fd, side)
408 fd_p fd;
409 int side;
410 {
411 if (fd->side == side)
412 return;
413
414 /* select the requested side */
415 if (side == 0)
416 ciab.prb &= ~CIAB_PRB_SIDE;
417 else
418 ciab.prb |= CIAB_PRB_SIDE;
419 delay(fd->ft->side_time);
420 fd->side = side;
421 }
422
423 /*
424 * Select the direction to use for the current particular drive.
425 */
426 void
427 fd_select_dir(fd, dir)
428 fd_p fd;
429 int dir;
430 {
431 if (fd->dir == dir)
432 return;
433
434 /* select the requested direction */
435 if (dir == 0)
436 ciab.prb &= ~CIAB_PRB_DIR;
437 else
438 ciab.prb |= CIAB_PRB_DIR;
439 delay(fd->ft->settle_time);
440 fd->dir = dir;
441 }
442
443 /*
444 * Seek the drive to track 0.
445 * The drive must be active and the motor must be running.
446 * Returns standard floppy error code. /* XXXX doesn't return anything
447 */
448 void
449 fd_calibrate(fd)
450 fd_p fd;
451 {
452 fd_select_dir(fd, 1);
453
454 /* loop until we hit track 0 */
455 while (ciaa.pra & CIAA_PRA_TK0) {
456 fd_step();
457 delay(4);
458 }
459
460 /* set known values */
461 fd->cyl = 0;
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 int delay_time;
476
477 cyl = track >> 1;
478 side = (track % 2) ^ 1;
479
480 if (fd->cyl == -1)
481 fd_calibrate(fd);
482
483 fd_select_side(fd, side);
484
485 if (cyl < fd->cyl) {
486 dir = 1;
487 cnt = fd->cyl - cyl;
488 } else {
489 dir = 0;
490 cnt = cyl - fd->cyl;
491 }
492
493 fd_select_dir(fd, dir);
494
495 if (cnt) {
496 while (cnt) {
497 delay_time = fd->ft->step_delay;
498 if (dir != fd->dir)
499 delay_time += fd->ft->settle_time;
500 fd_step();
501 delay(delay_time);
502 --cnt;
503 }
504 delay(fd->ft->settle_time);
505 }
506
507 fd->cyl = cyl;
508 }
509
510 void
511 encode(data, dest, csum)
512 u_long data;
513 u_long *dest, *csum;
514 {
515 u_long data2;
516
517 data &= 0x55555555;
518 data2 = data ^ 0x55555555;
519 data |= ((data2 >> 1) | 0x80000000) & (data2 << 1);
520
521 if (*(dest - 1) & 0x00000001)
522 data &= 0x7FFFFFFF;
523
524 *csum ^= data;
525 *dest = data;
526 }
527
528 u_long
529 encode_long(data, dest)
530 u_long data;
531 u_long *dest;
532 {
533 u_long csum;
534
535 csum = 0;
536
537 encode(data >> 1, dest, &csum);
538 encode(data, dest + 1, &csum);
539
540 return(csum & 0x55555555);
541 }
542
543 void
544 encode_block(dest, from, len, csum)
545 u_long *dest, *csum;
546 u_char *from;
547 int len;
548 {
549 int cnt, to_cnt = 0;
550 u_long data, *src;
551
552 to_cnt = 0;
553 src = (u_long *)from;
554
555 /* odd bits */
556 for (cnt = 0; cnt < len / 4; cnt++) {
557 data = src[cnt] >> 1;
558 encode(data, dest + to_cnt++, csum);
559 }
560
561 /* even bits */
562 for (cnt = 0; cnt < len / 4; cnt++) {
563 data = src[cnt];
564 encode(data, dest + to_cnt++, csum);
565 }
566
567 *csum &= 0x55555555;
568 }
569
570 void
571 correct(raw)
572 u_long *raw;
573 {
574 u_char data, *ptr;
575
576 ptr = (u_char *)raw;
577
578 data = *ptr;
579 if (*(ptr - 1) & 0x01) { /* XXXX will choke on old GVP's */
580 *ptr = data & 0x7f;
581 return;
582 }
583
584 if (data & 0x40)
585 return;
586
587 *ptr |= 0x80;
588 }
589
590 /*
591 * amiga_write converts track/labels data to raw track data
592 */
593 void
594 amiga_write(fd)
595 fd_p fd;
596 {
597 u_long *raw, csum, format;
598 u_char *data, *labels;
599 int cnt, track;
600
601 raw = (u_long *)raw_buf; /* XXXX never used while intr? */
602 /* XXXX never waits after here? */
603 data = fd->buf_data;
604 labels = fd->buf_labels;
605 track = fd->buf_track;
606
607 /* gap space */
608 for (cnt = 0; cnt < 414; cnt++)
609 *raw++ = 0xaaaaaaaa;
610
611 /* sectors */
612 for (cnt = 0; cnt < 11; cnt++) {
613 *raw = 0xaaaaaaaa;
614 correct(raw);
615 ++raw;
616
617 *raw++ = 0x44894489;
618
619 format = 0xff000000 | (track << 16) | (cnt << 8) | (11 - cnt);
620 csum = encode_long(format,raw);
621 raw += 2;
622
623 encode_block(raw, labels + cnt * 16, 16, &csum);
624 raw += 8;
625 csum = encode_long(csum, raw);
626 raw += 2;
627
628 csum = 0;
629 encode_block(raw+2, data + cnt * 512, 512, &csum);
630 csum = encode_long(csum, raw);
631 raw += 256 + 2;
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 * sector = 10, 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 != 10) {
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)) == 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 %ld, %ld\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 int i;
795
796 id = 0;
797
798 /* loop and read disk ID */
799 for (i = 0; i < 32; i++) {
800 SELECT(SELMASK(unit));
801
802 /* read and store value of DSKRDY */
803 id <<= 1; /* XXXX 0 << 1? */
804 id |= (ciaa.pra & CIAA_PRA_RDY) ? 0 : 1;
805
806 DESELECT(SELMASK(unit));
807 }
808 }
809
810 u_long
811 get_drive_id(unit)
812 int unit;
813 {
814 int i, t;
815 u_long id;
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 (i = 0; i < 32; i++) {
834 *b_ptr &= mask1;
835 t = (*a_ptr) & CIAA_PRA_RDY;
836 id = (id << 1) | (t ? 0 : 1);
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 if (type == -1) {
881 /* XXXX */
882 printf("fd_probe: unsupported drive type %08x found\n", id);
883 return;
884 }
885
886 fd->type = type;
887 fd->ft = &drive_types[type];
888 if (fd->ft->tracks == 0) {
889 /* XXXX */
890 printf("no drive type %d\n", type);
891 }
892 fd->side = -1;
893 fd->dir = -1;
894 fd->cyl = -1;
895
896 fd->sects = 11 * drive_types[type].sect_mult;
897 fd->size = fd->sects *
898 drive_types[type].tracks *
899 drive_types[type].heads;
900 fd->flags = 0;
901 }
902
903 void
904 track_read(fdc, fd, track)
905 fdc_p fdc;
906 fd_p fd;
907 int track;
908 {
909 u_long len;
910
911 fd->buf_track = track;
912 fdc->state = WAIT_READ;
913 timeout((timeout_t)fd_timeout, (caddr_t)fdc, 2 * hz);
914
915 fd_seek(fd, track);
916
917 len = fd->ft->read_size >> 1;
918
919 /* setup adkcon bits correctly */
920 custom.adkcon = ADKF_MSBSYNC;
921 custom.adkcon = ADKF_SETCLR | ADKF_WORDSYNC | ADKF_FAST;
922
923 custom.dsksync = MFM_SYNC;
924
925 custom.dsklen = 0;
926 delay(fd->ft->side_time);
927
928 custom.dskpt = (u_char *)kvtop(raw_buf);
929 custom.dsklen = len | DSKLEN_DMAEN;
930 custom.dsklen = len | DSKLEN_DMAEN;
931 }
932
933 void
934 track_write(fdc, fd)
935 fdc_p fdc;
936 fd_p fd;
937 {
938 int track;
939 u_long len;
940 u_short adk;
941
942 amiga_write(fd);
943
944 track = fd->buf_track;
945 fd->write_cnt += 1;
946
947 fdc->saved = fdc->state;
948 fdc->state = WAIT_WRITE;
949 timeout((timeout_t)fd_timeout, (caddr_t)fdc, 2 * hz);
950
951 fd_seek(fd, track);
952
953 len = fd->ft->write_size >> 1;
954
955 if ((ciaa.pra & CIAA_PRA_WPRO) == 0)
956 return;
957
958 /* clear adkcon bits */
959 custom.adkcon = ADKF_PRECOMP1 | ADKF_PRECOMP0 | ADKF_WORDSYNC |
960 ADKF_MSBSYNC;
961
962 /* set appropriate adkcon bits */
963 adk = ADKF_SETCLR | ADKF_FAST;
964 if (track >= fd->ft->precomp2)
965 adk |= ADKF_PRECOMP1;
966 else if (track >= fd->ft->precomp1)
967 adk |= ADKF_PRECOMP0;
968 custom.adkcon = adk;
969
970 custom.dsklen = DSKLEN_WRITE;
971 delay(fd->ft->side_time);
972
973 custom.dskpt = (u_char *)kvtop(raw_buf); /* XXXX again raw */
974 custom.dsklen = len | DSKLEN_DMAEN | DSKLEN_WRITE;
975 custom.dsklen = len | DSKLEN_DMAEN | DSKLEN_WRITE;
976 }
977
978 /*
979 * Floppy Device Code
980 */
981 int
982 fdattach(ad)
983 struct amiga_device *ad;
984 {
985 int fdcu = 0;
986 fdc_p fdc = fdc_data + fdcu;
987 int i;
988 unsigned long id;
989 int type;
990
991 fdc->fdcu = fdcu;
992 fdc->state = FINDWORK;
993 fdc->fd = NULL;
994 fdc->motor_fdu = -1;
995
996 for (i = 0; i < DRVS_PER_CTLR; i++) {
997 fdc->fd_data[i].fdu = i;
998 fdc->fd_data[i].flags = 0;
999
1000 fdc->fd_data[i].buf_track = -1;
1001 fdc->fd_data[i].buf_dirty = 0;
1002 fdc->fd_data[i].buf_data =
1003 malloc(MAX_SECTS * 512, M_DEVBUF, 0);
1004 fdc->fd_data[i].buf_labels =
1005 malloc(MAX_SECTS * 16, M_DEVBUF, 0);
1006
1007 if (fdc->fd_data[i].buf_data == NULL ||
1008 fdc->fd_data[i].buf_labels == NULL) {
1009 printf("Cannot alloc buffer memory for fd device\n");
1010 return(0);
1011 }
1012
1013 id = get_drive_id(i);
1014 type = get_drive_type(id);
1015
1016 if (type != -1 && drive_types[type].tracks != 0) {
1017 printf("floppy drive %d: %s\n", i,
1018 drive_types[type].name);
1019 }
1020 }
1021
1022 raw_buf = (char *)alloc_chipmem(30000);
1023 if (raw_buf == NULL) {
1024 printf("Cannot alloc chipmem for fd device\n");
1025 return 0;
1026 }
1027
1028 /* enable disk DMA */
1029 custom.dmacon = DMAF_SETCLR | DMAF_DISK;
1030
1031 /* enable interrupts for IRQ_DSKBLK */
1032 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_FLG;
1033 custom.intena = INTF_SETCLR | INTF_SOFTINT;
1034
1035 /* enable disk block interrupts */
1036 custom.intena = INTF_SETCLR | INTF_DSKBLK;
1037
1038 return(1);
1039 }
1040
1041 int
1042 Fdopen(dev, flags)
1043 dev_t dev;
1044 int flags;
1045 {
1046 fdcu_t fdcu;
1047 fdc_p fdc;
1048 fdu_t fdu;
1049 fd_p fd;
1050
1051 fdcu = 0;
1052 fdc = fdc_data + fdcu;
1053 fdu = UNIT(dev);
1054 fd = fdc->fd_data + fdu;
1055
1056 /* check bounds */
1057 if (fdu >= DRVS_PER_CTLR)
1058 return(ENXIO);
1059
1060 fd_probe(fd);
1061 if (fd->ft == NULL || fd->ft->tracks == 0)
1062 return(ENXIO);
1063
1064 fd->flags |= FDF_OPEN;
1065 fd->write_cnt = 0;
1066
1067 return(0);
1068 }
1069
1070 int
1071 fdclose(dev, flags)
1072 dev_t dev;
1073 int flags;
1074 {
1075 struct buf *dp,*bp;
1076 fdcu_t fdcu;
1077 fdc_p fdc;
1078 fdu_t fdu;
1079 fd_p fd;
1080
1081 fdcu = 0;
1082 fdc = fdc_data + fdcu;
1083 fdu = UNIT(dev);
1084 fd = fdc->fd_data + fdu;
1085
1086
1087 /* wait until activity is done for this drive */
1088 /* XXXX ACK! sleep.. */
1089 do {
1090 dp = &(fd->head);
1091 bp = dp->b_actf;
1092 } while (bp);
1093
1094 /* XXXX */
1095 printf("wrote %d tracks (%d)\n", fd->write_cnt, fd->buf_dirty);
1096
1097 fd->buf_track = -1;
1098 fd->buf_dirty = 0;
1099 fd->flags &= ~FDF_OPEN;
1100
1101 return(0);
1102 }
1103
1104 int
1105 fdioctl(dev, cmd, data, flag, p)
1106 dev_t dev;
1107 int cmd, flag;
1108 caddr_t data;
1109 struct proc *p;
1110 {
1111 struct disklabel *fd_label;
1112 fdcu_t fdcu;
1113 fdc_p fdc;
1114 fdu_t fdu;
1115 fd_p fd;
1116 int error;
1117
1118 fdcu = 0;
1119 fdc = fdc_data + fdcu;
1120 fdu = UNIT(dev);
1121 fd = fdc->fd_data + fdu;
1122 error = 0;
1123
1124 if (cmd != DIOCGDINFO)
1125 return (EINVAL);
1126
1127 fd_label = (struct disklabel *)data;
1128
1129 bzero(fd_label, sizeof(fd_label));
1130 fd_label->d_magic = DISKMAGIC;
1131 fd_label->d_type = DTYPE_FLOPPY;
1132 strncpy(fd_label->d_typename, "fd", sizeof(fd_label->d_typename) - 1);
1133 strcpy(fd_label->d_packname, "some pack");
1134
1135 fd_label->d_secsize = 512;
1136 fd_label->d_nsectors = 11;
1137 fd_label->d_ntracks = 2;
1138 fd_label->d_ncylinders = 80;
1139 fd_label->d_secpercyl = fd_label->d_nsectors * fd_label->d_ntracks;
1140 fd_label->d_secperunit= fd_label->d_ncylinders * fd_label->d_secpercyl;
1141
1142 fd_label->d_magic2 = DISKMAGIC;
1143 fd_label->d_partitions[0].p_offset = 0;
1144 fd_label->d_partitions[0].p_size = fd_label->d_secperunit;
1145 fd_label->d_partitions[0].p_fstype = FS_UNUSED;
1146 fd_label->d_npartitions = 1;
1147
1148 fd_label->d_checksum = 0;
1149 fd_label->d_checksum = dkcksum(fd_label);
1150
1151 return(0);
1152 }
1153
1154 int
1155 fdsize(dev)
1156 dev_t dev;
1157 {
1158 /* check UNIT? */
1159 return((fdc_data + 0)->fd_data[UNIT(dev)].size);
1160 }
1161
1162 void
1163 fdstrategy(bp)
1164 struct buf *bp;
1165 {
1166 fdcu_t fdcu;
1167 fdc_p fdc;
1168 fdu_t fdu;
1169 fd_p fd;
1170 long nblocks, blknum;
1171 struct buf *dp;
1172 int s;
1173
1174 fdcu = 0;
1175 fdc = fdc_data + fdcu;
1176 fdu = UNIT(bp->b_dev);
1177 fd = fdc->fd_data + fdu;
1178
1179 if (bp->b_blkno < 0) {
1180 /* XXXX */
1181 printf("fdstrat error: fdu = %d, blkno = %d, bcount = %d\n",
1182 fdu, bp->b_blkno, bp->b_bcount);
1183 bp->b_error = EINVAL;
1184 bp->b_flags |= B_ERROR;
1185 biodone(bp);
1186 return;
1187 }
1188
1189 /*
1190 * Set up block calculations.
1191 */
1192 blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / FDBLK;
1193 nblocks = fd->sects * fd->ft->tracks * fd->ft->heads;
1194 if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
1195 /* XXXX */
1196 printf("at end of disk\n");
1197 bp->b_error = ENOSPC;
1198 bp->b_flags |= B_ERROR;
1199 biodone(bp);
1200 return;
1201 }
1202
1203 bp->b_cylin = blknum; /* set here for disksort */
1204 dp = &(fd->head);
1205
1206 s = splbio();
1207 disksort(dp, bp);
1208 untimeout((timeout_t)fd_turnoff, (caddr_t)fdc); /* a good idea */
1209 fdstart(fdc);
1210 splx(s);
1211 }
1212
1213 /*
1214 * We have just queued something.. if the controller is not busy
1215 * then simulate the case where it has just finished a command
1216 * So that it (the interrupt routine) looks on the queue for more
1217 * work to do and picks up what we just added.
1218 * If the controller is already busy, we need do nothing, as it
1219 * will pick up our work when the present work completes
1220 */
1221 void
1222 fdstart(fdc)
1223 fdc_p fdc;
1224 {
1225 int s;
1226
1227 s = splbio();
1228 if (fdc->state == FINDWORK)
1229 fdintr(fdc->fdcu);
1230 splx(s);
1231 }
1232
1233 /*
1234 * just ensure it has the right spl
1235 */
1236 void
1237 fd_pseudointr(fdc)
1238 fdc_p fdc;
1239 {
1240 int s;
1241
1242 s = splbio();
1243 fdintr(fdc->fdcu);
1244 splx(s);
1245 }
1246
1247 void
1248 fd_timeout(fdc)
1249 fdc_p fdc;
1250 {
1251 struct buf *dp,*bp;
1252 fd_p fd;
1253
1254 fd = fdc->fd;
1255 dp = &fd->head;
1256 bp = dp->b_actf;
1257
1258 /* XXXX */
1259 printf("fd%d: Operation timeout\n", fd->fdu);
1260 if (bp) {
1261 retrier(fdc);
1262 fdc->state = DONE_IO;
1263 if (fdc->retry < 6)
1264 fdc->retry = 6;
1265 } else {
1266 fdc->fd = NULL;
1267 fdc->state = FINDWORK;
1268 }
1269
1270 fd_pseudointr(fdc);
1271 }
1272
1273 /*
1274 * keep calling the state machine until it returns a 0
1275 * ALWAYS called at SPLBIO
1276 */
1277 void
1278 fdintr(fdcu)
1279 fdcu_t fdcu;
1280 {
1281 fdc_p fdc;
1282
1283 fdc = fdc_data + fdcu;
1284 while (fdstate(fdc))
1285 ;
1286 }
1287
1288 /*
1289 * The controller state machine.
1290 * if it returns a non zero value, it should be called again immediatly
1291 */
1292 int
1293 fdstate(fdc)
1294 fdc_p fdc;
1295 {
1296 struct buf *dp,*bp;
1297 int track, read, sec, i;
1298 u_long blknum;
1299 fd_p fd;
1300
1301 fd = fdc->fd;
1302
1303 if (fd == NULL) {
1304 /* search for a unit do work with */
1305 for (i = 0; i < DRVS_PER_CTLR; i++) {
1306 fd = fdc->fd_data + i;
1307 dp = &(fd->head);
1308 bp = dp->b_actf;
1309 if (bp) {
1310 fdc->fd = fd;
1311 break;
1312 }
1313 }
1314
1315 if (fdc->fd)
1316 return(1);
1317
1318 fdc->state = FINDWORK;
1319 TRACE1("[fdc%d IDLE]\n", fdc->fdcu);
1320 return(0);
1321 }
1322
1323 dp = &(fd->head);
1324 bp = dp->b_actf;
1325
1326 blknum = (u_long)bp->b_blkno * DEV_BSIZE / FDBLK + fd->skip / FDBLK;
1327 track = blknum / fd->sects;
1328 sec = blknum % fd->sects;
1329
1330 read = bp->b_flags & B_READ;
1331 TRACE1("fd%d", fd->fdu);
1332 TRACE1("[%s]", fdstates[fdc->state]);
1333 TRACE1("(0x%x) ", fd->flags);
1334 TRACE1("%d\n", fd->buf_track);
1335
1336 untimeout((timeout_t)fd_turnoff, (caddr_t)fdc);
1337 timeout((timeout_t)fd_turnoff, (caddr_t)fdc, 4 * hz);
1338
1339 switch (fdc->state) {
1340 case FINDWORK:
1341 if (!bp) {
1342 if (fd->buf_dirty) {
1343 track_write(fdc, fd);
1344 return(0);
1345 }
1346 fdc->fd = NULL;
1347 return(1);
1348 }
1349
1350 fdc->state = DOSEEK;
1351 fdc->retry = 0;
1352 fd->skip = 0;
1353 return(1);
1354 case DOSEEK:
1355 fd_turnon(fdc, fd->fdu);
1356
1357 /*
1358 * If not started, error starting it
1359 */
1360 if (fdc->motor_fdu != fd->fdu) {
1361 /* XXXX */
1362 printf("motor not on!\n");
1363 }
1364
1365 /*
1366 * If track not in buffer, read it in
1367 */
1368 if (fd->buf_track != track) {
1369 TRACE1("do track %d\n", track);
1370
1371 if (fd->buf_dirty)
1372 track_write(fdc, fd);
1373 else
1374 track_read(fdc, fd, track);
1375 return(0);
1376 }
1377
1378 fdc->state = DO_IO;
1379 return(1);
1380 case DO_IO:
1381 if (read)
1382 bcopy(&fd->buf_data[sec * FDBLK],
1383 bp->b_un.b_addr + fd->skip, FDBLK);
1384 else {
1385 bcopy(bp->b_un.b_addr + fd->skip,
1386 &fd->buf_data[sec * FDBLK], FDBLK);
1387 fd->buf_dirty = 1;
1388 if (IMMED_WRITE) {
1389 fdc->state = DONE_IO;
1390 track_write(fdc, fd);
1391 return(0);
1392 }
1393 }
1394 case DONE_IO:
1395 fd->skip += FDBLK;
1396 if (fd->skip < bp->b_bcount)
1397 fdc->state = DOSEEK;
1398 else {
1399 fd->skip = 0;
1400 bp->b_resid = 0;
1401 dp->b_actf = bp->b_actf;
1402 biodone(bp);
1403 fdc->state = FINDWORK;
1404 }
1405 return(1);
1406 case WAIT_READ:
1407 untimeout((timeout_t)fd_timeout, (caddr_t)fdc);
1408 custom.dsklen = 0;
1409 amiga_read(fd);
1410 fdc->state = DO_IO;
1411 return(1);
1412 case WAIT_WRITE:
1413 untimeout((timeout_t)fd_timeout, (caddr_t)fdc);
1414 custom.dsklen = 0;
1415 fdc->state = fdc->saved;
1416 fd->buf_dirty = 0;
1417 return(1);
1418 default:
1419 /* XXXX */
1420 printf("Unexpected FD int->%d\n", fdc->state);
1421 return 0;
1422 }
1423
1424 /* Come back immediatly to new state */
1425 return(1);
1426 }
1427
1428 int
1429 retrier(fdc)
1430 fdc_p fdc;
1431 {
1432 struct buf *dp,*bp;
1433 fd_p fd;
1434
1435 fd = fdc->fd;
1436 dp = &(fd->head);
1437 bp = dp->b_actf;
1438
1439 #if 0
1440 switch(fdc->retry) {
1441 case 0:
1442 case 1:
1443 case 2:
1444 fdc->state = SEEKCOMPLETE;
1445 break;
1446 case 3:
1447 case 4:
1448 case 5:
1449 fdc->state = STARTRECAL;
1450 break;
1451 case 6:
1452 fdc->state = RESETCTLR;
1453 break;
1454 case 7:
1455 break;
1456 default:
1457 #endif
1458 /* XXXX */
1459 printf("fd%d: hard error\n", fd->fdu);
1460
1461 bp->b_flags |= B_ERROR;
1462 bp->b_error = EIO;
1463 bp->b_resid = bp->b_bcount - fd->skip;
1464 dp->b_actf = bp->b_actf;
1465 fd->skip = 0;
1466 biodone(bp);
1467 fdc->state = FINDWORK;
1468 return(1);
1469 #if 0
1470 fdc->retry++;
1471 return(1);
1472 #endif
1473 }
1474
1475 #endif
1476