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