fd.c revision 1.29 1 /* $NetBSD: fd.c,v 1.29 1996/04/21 21:11:01 veego Exp $ */
2
3 /*
4 * Copyright (c) 1994 Christian E. Hopps
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Christian E. Hopps.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/malloc.h>
36 #include <sys/buf.h>
37 #include <sys/device.h>
38 #include <sys/ioctl.h>
39 #include <sys/fcntl.h>
40 #include <sys/disklabel.h>
41 #include <sys/disk.h>
42 #include <sys/dkbad.h>
43 #include <sys/proc.h>
44 #include <sys/cpu.h>
45 #include <machine/cpu.h>
46 #include <amiga/amiga/device.h>
47 #include <amiga/amiga/custom.h>
48 #include <amiga/amiga/cia.h>
49 #include <amiga/amiga/cc.h>
50
51 #include <sys/conf.h>
52 #include <machine/conf.h>
53
54 enum fdc_bits { FDB_CHANGED = 2, FDB_PROTECT, FDB_CYLZERO, FDB_READY };
55 /*
56 * partitions in fd represent different format floppies
57 * partition a is 0 etc..
58 */
59 enum fd_parttypes {
60 FDAMIGAPART = 0,
61 #ifdef not_yet
62 FDMSDOSPART,
63 #endif
64 FDMAXPARTS
65 };
66
67 #define FDBBSIZE (8192)
68 #define FDSBSIZE (8192)
69
70 #define b_cylin b_resid
71 #define FDUNIT(dev) DISKUNIT(dev)
72 #define FDPART(dev) DISKPART(dev)
73 #define FDMAKEDEV(m, u, p) MAKEDISKDEV((m), (u), (p))
74
75 #define FDNHEADS (2) /* amiga drives always have 2 heads */
76 #define FDSECSIZE (512) /* amiga drives always have 512 byte sectors */
77 #define FDSECLWORDS (128)
78
79 #define FDSETTLEDELAY (18000) /* usec delay after seeking after switch dir */
80 #define FDSTEPDELAY (3500) /* usec delay after steping */
81 #define FDPRESIDEDELAY (1000) /* usec delay before writing can occur */
82 #define FDWRITEDELAY (1300) /* usec delay after write */
83
84 #define FDSTEPOUT (1) /* decrease track step */
85 #define FDSTEPIN (0) /* increase track step */
86
87 #define FDCUNITMASK (0x78) /* mask for all units (bits 6-3) */
88
89 #define FDRETRIES (2) /* default number of retries */
90 #define FDMAXUNITS (4) /* maximum number of supported units */
91
92 #define DISKLEN_READ (0) /* fake mask for reading */
93 #define DISKLEN_WRITE (1 << 14) /* bit for writing */
94 #define DISKLEN_DMAEN (1 << 15) /* dma go */
95 #define DMABUFSZ ((DISKLEN_WRITE - 1) * 2) /* largest dma possible */
96
97 #define FDMFMSYNC (0x4489)
98
99 /*
100 * floppy device type
101 */
102 struct fdtype {
103 u_int driveid; /* drive identification (from drive) */
104 u_int ncylinders; /* number of cylinders on drive */
105 u_int amiga_nsectors; /* number of sectors per amiga track */
106 u_int msdos_nsectors; /* number of sectors per msdos track */
107 u_int nreadw; /* number of words (short) read per track */
108 u_int nwritew; /* number of words (short) written per track */
109 u_int gap; /* track gap size in long words */
110 u_int precomp[2]; /* 1st and 2nd precomp values */
111 char *desc; /* description of drive type (useq) */
112 };
113
114 /*
115 * floppy disk device data
116 */
117 struct fd_softc {
118 struct device sc_dv; /* generic device info; must come first */
119 struct disk dkdev; /* generic disk info */
120 struct buf bufq; /* queue of buf's */
121 struct fdtype *type;
122 void *cachep; /* cached track data (write through) */
123 int cachetrk; /* cahced track -1 for none */
124 int hwunit; /* unit for amiga controlling hw */
125 int unitmask; /* mask for cia select deslect */
126 int pstepdir; /* previous step direction */
127 int curcyl; /* current curcyl head positioned on */
128 int flags; /* misc flags */
129 int wlabel;
130 int stepdelay; /* useq to delay after seek user setable */
131 int nsectors; /* number of sectors per track */
132 int openpart; /* which partition [ab] == [12] is open */
133 short retries; /* number of times to retry failed io */
134 short retried; /* number of times current io retried */
135 };
136
137 /* fd_softc->flags */
138 #define FDF_MOTORON (0x01) /* motor is running */
139 #define FDF_MOTOROFF (0x02) /* motor is waiting to be turned off */
140 #define FDF_WMOTOROFF (0x04) /* unit wants a wakeup after off */
141 #define FDF_DIRTY (0x08) /* track cache needs write */
142 #define FDF_WRITEWAIT (0x10) /* need to head select delay on next setpos */
143 #define FDF_HAVELABEL (0x20) /* label is valid */
144 #define FDF_JUSTFLUSH (0x40) /* don't bother caching track. */
145 #define FDF_NOTRACK0 (0x80) /* was not able to recalibrate drive */
146
147 int fdc_wantwakeup;
148 int fdc_side;
149 void *fdc_dmap;
150 struct fd_softc *fdc_indma;
151
152 struct fdcargs {
153 struct fdtype *type;
154 int unit;
155 };
156
157 int fdcmatch __P((struct device *, void *, void *));
158 void fdcattach __P((struct device *, struct device *, void *));
159 int fdcprint __P((void *, char *));
160 int fdmatch __P((struct device *, void *, void *));
161 void fdattach __P((struct device *, struct device *, void *));
162
163 void fdintr __P((int));
164 void fdstrategy __P((struct buf *));
165 int fdloaddisk __P((struct fd_softc *));
166 int fdgetdisklabel __P((struct fd_softc *, dev_t));
167 int fdsetdisklabel __P((struct fd_softc *, struct disklabel *));
168 int fdputdisklabel __P((struct fd_softc *, dev_t));
169 struct fdtype * fdcgetfdtype __P((int));
170 void fdmotoroff __P((void *));
171 void fdsetpos __P((struct fd_softc *, int, int));
172 void fdselunit __P((struct fd_softc *));
173 void fdstart __P((struct fd_softc *));
174 void fdcont __P((struct fd_softc *));
175 void fddmastart __P((struct fd_softc *, int));
176 void fdcalibrate __P((void *));
177 void fddmadone __P((struct fd_softc *, int));
178 void fddone __P((struct fd_softc *));
179 void fdfindwork __P((int));
180 void fdminphys __P((struct buf *));
181 void fdcachetoraw __P((struct fd_softc *));
182 u_long *fdfindsync __P((u_long *, u_long *));
183 int fdrawtocache __P((struct fd_softc *));
184 u_long *mfmblkencode __P((u_long *, u_long *, u_long *, int));
185 u_long *mfmblkdecode __P((u_long *, u_long *, u_long *, int));
186
187 struct dkdriver fddkdriver = { fdstrategy };
188
189 /*
190 * read size is (nsectors + 1) * mfm secsize + gap bytes + 2 shorts
191 * write size is nsectors * mfm secsize + gap bytes + 3 shorts
192 * the extra shorts are to deal with a dma hw bug in the controller
193 * they are probably too much (I belive the bug is 1 short on write and
194 * 3 bits on read) but there is no need to be cheap here.
195 */
196 #define MAXTRKSZ (22 * FDSECSIZE)
197 struct fdtype fdtype[] = {
198 { 0x00000000, 80, 11, 9, 7358, 6815, 414, { 80, 161 }, "3.5dd" },
199 { 0x55555555, 40, 11, 9, 7358, 6815, 414, { 80, 161 }, "5.25dd" },
200 { 0xAAAAAAAA, 80, 22, 18, 14716, 13630, 828, { 80, 161 }, "3.5hd" }
201 };
202 int nfdtype = sizeof(fdtype) / sizeof(*fdtype);
203
204 struct cfattach fd_ca = {
205 sizeof(struct fd_softc), fdmatch, fdattach
206 };
207
208 struct cfdriver fd_cd = {
209 NULL, "fd", DV_DISK, NULL, 0
210 };
211
212 struct cfattach fdc_ca = {
213 sizeof(struct device), fdcmatch, fdcattach
214 };
215
216 struct cfdriver fdc_cd = {
217 NULL, "fdc", DV_DULL, NULL, 0
218 };
219
220 /*
221 * all hw access through macros, this helps to hide the active low
222 * properties
223 */
224
225 #define FDUNITMASK(unit) (1 << (3 + (unit)))
226
227 /*
228 * select units using mask
229 */
230 #define FDSELECT(um) do { ciab.prb &= ~(um); } while (0)
231
232 /*
233 * deselect units using mask
234 */
235 #define FDDESELECT(um) do { ciab.prb |= (um); delay(1); } while (0)
236
237 /*
238 * test hw condition bits
239 */
240 #define FDTESTC(bit) ((ciaa.pra & (1 << (bit))) == 0)
241
242 /*
243 * set motor for select units, true motor on else off
244 */
245 #define FDSETMOTOR(on) do { \
246 if (on) ciab.prb &= ~CIAB_PRB_MTR; else ciab.prb |= CIAB_PRB_MTR; \
247 } while (0)
248
249 /*
250 * set head for select units
251 */
252 #define FDSETHEAD(head) do { \
253 if (head) ciab.prb &= ~CIAB_PRB_SIDE; else ciab.prb |= CIAB_PRB_SIDE; \
254 delay(1); } while (0)
255
256 /*
257 * select direction, true towards spindle else outwards
258 */
259 #define FDSETDIR(in) do { \
260 if (in) ciab.prb &= ~CIAB_PRB_DIR; else ciab.prb |= CIAB_PRB_DIR; \
261 delay(1); } while (0)
262
263 /*
264 * step the selected units
265 */
266 #define FDSTEP do { \
267 ciab.prb &= ~CIAB_PRB_STEP; ciab.prb |= CIAB_PRB_STEP; \
268 } while (0)
269
270 #define FDDMASTART(len, towrite) do { \
271 int dmasz = (len) | ((towrite) ? DISKLEN_WRITE : 0) | DISKLEN_DMAEN; \
272 custom.dsklen = dmasz; custom.dsklen = dmasz; } while (0)
273
274 #define FDDMASTOP do { custom.dsklen = 0; } while (0)
275
276
277 int
278 fdcmatch(pdp, match, auxp)
279 struct device *pdp;
280 void *match, *auxp;
281 {
282 struct cfdata *cfp = match;
283
284 if (matchname("fdc", auxp) == 0 || cfp->cf_unit != 0)
285 return(0);
286 if ((fdc_dmap = alloc_chipmem(DMABUFSZ)) == NULL) {
287 printf("fdc: unable to allocate dma buffer\n");
288 return(0);
289 }
290 return(1);
291 }
292
293 void
294 fdcattach(pdp, dp, auxp)
295 struct device *pdp, *dp;
296 void *auxp;
297 {
298 struct fdcargs args;
299
300 printf(": dmabuf pa 0x%x\n", kvtop(fdc_dmap));
301 args.unit = 0;
302 args.type = fdcgetfdtype(args.unit);
303
304 fdc_side = -1;
305 config_found(dp, &args, fdcprint);
306 for (args.unit++; args.unit < FDMAXUNITS; args.unit++) {
307 if ((args.type = fdcgetfdtype(args.unit)) == NULL)
308 continue;
309 config_found(dp, &args, fdcprint);
310 }
311 }
312
313 int
314 fdcprint(auxp, pnp)
315 void *auxp;
316 char *pnp;
317 {
318 struct fdcargs *fcp;
319
320 fcp = auxp;
321 if (pnp)
322 printf("fd%d at %s unit %d:", fcp->unit, pnp,
323 fcp->type->driveid);
324 return(UNCONF);
325 }
326
327 /*ARGSUSED*/
328 int
329 fdmatch(pdp, match, auxp)
330 struct device *pdp;
331 void *match, *auxp;
332 {
333 struct cfdata *cfp = match;
334
335 #define cf_unit cf_loc[0]
336 struct fdcargs *fdap;
337
338 fdap = auxp;
339 if (cfp->cf_unit == fdap->unit || cfp->cf_unit == -1)
340 return(1);
341 return(0);
342 #undef cf_unit
343 }
344
345 void
346 fdattach(pdp, dp, auxp)
347 struct device *pdp, *dp;
348 void *auxp;
349 {
350 struct fdcargs *ap;
351 struct fd_softc *sc;
352
353 ap = auxp;
354 sc = (struct fd_softc *)dp;
355
356 sc->curcyl = sc->cachetrk = -1;
357 sc->openpart = -1;
358 sc->type = ap->type;
359 sc->hwunit = ap->unit;
360 sc->unitmask = 1 << (3 + ap->unit);
361 sc->retries = FDRETRIES;
362 sc->stepdelay = FDSTEPDELAY;
363 printf(" unit %d: %s %d cyl, %d head, %d sec [%d sec], 512 bytes/sec\n",
364 sc->hwunit, sc->type->desc, sc->type->ncylinders, FDNHEADS,
365 sc->type->amiga_nsectors, sc->type->msdos_nsectors);
366
367 /*
368 * Initialize and attach the disk structure.
369 */
370 sc->dkdev.dk_name = sc->sc_dv.dv_xname;
371 sc->dkdev.dk_driver = &fddkdriver;
372 disk_attach(&sc->dkdev);
373
374 /*
375 * calibrate the drive
376 */
377 fdsetpos(sc, 0, 0);
378 fdsetpos(sc, sc->type->ncylinders, 0);
379 fdsetpos(sc, 0, 0);
380 fdmotoroff(sc);
381
382 /*
383 * enable disk related interrupts
384 */
385 custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_DISK;
386 /* XXX why softint */
387 custom.intena = INTF_SETCLR |INTF_SOFTINT | INTF_DSKBLK;
388 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_FLG;
389 }
390
391 /*ARGSUSED*/
392 int
393 fdopen(dev, flags, devtype, p)
394 dev_t dev;
395 int flags, devtype;
396 struct proc *p;
397 {
398 struct fd_softc *sc;
399 int wasopen, fwork, error, s;
400
401 error = 0;
402
403 if (FDPART(dev) >= FDMAXPARTS)
404 return(ENXIO);
405
406 if ((sc = getsoftc(fd_cd, FDUNIT(dev))) == NULL)
407 return(ENXIO);
408 if (sc->flags & FDF_NOTRACK0)
409 return(ENXIO);
410 if (sc->cachep == NULL)
411 sc->cachep = malloc(MAXTRKSZ, M_DEVBUF, M_WAITOK);
412
413 s = splbio();
414 /*
415 * if we are sleeping in fdclose(); waiting for a chance to
416 * shut the motor off, do a sleep here also.
417 */
418 while (sc->flags & FDF_WMOTOROFF)
419 tsleep(fdmotoroff, PRIBIO, "fdopen", 0);
420
421 fwork = 0;
422 /*
423 * if not open let user open request type, otherwise
424 * ensure they are trying to open same type.
425 */
426 if (sc->openpart == FDPART(dev))
427 wasopen = 1;
428 else if (sc->openpart == -1) {
429 sc->openpart = FDPART(dev);
430 wasopen = 0;
431 } else {
432 wasopen = 1;
433 error = EPERM;
434 goto done;
435 }
436
437 /*
438 * wait for current io to complete if any
439 */
440 if (fdc_indma) {
441 fwork = 1;
442 fdc_wantwakeup++;
443 tsleep(fdopen, PRIBIO, "fdopen", 0);
444 }
445 if ((error = fdloaddisk(sc)) != 0)
446 goto done;
447 if ((error = fdgetdisklabel(sc, dev)) != 0)
448 goto done;
449 #ifdef FDDEBUG
450 printf(" open successful\n");
451 #endif
452 done:
453 /*
454 * if we requested that fddone()->fdfindwork() wake us, allow it to
455 * complete its job now
456 */
457 if (fwork)
458 fdfindwork(FDUNIT(dev));
459 splx(s);
460
461 /*
462 * if we were not open and we marked us so reverse that.
463 */
464 if (error && wasopen == 0)
465 sc->openpart = 0;
466 return(error);
467 }
468
469 /*ARGSUSED*/
470 int
471 fdclose(dev, flags, devtype, p)
472 dev_t dev;
473 int flags, devtype;
474 struct proc *p;
475 {
476 struct fd_softc *sc;
477 int s;
478
479 #ifdef FDDEBUG
480 printf("fdclose()\n");
481 #endif
482 sc = getsoftc(fd_cd, FDUNIT(dev));
483 s = splbio();
484 if (sc->flags & FDF_MOTORON) {
485 sc->flags |= FDF_WMOTOROFF;
486 tsleep(fdmotoroff, PRIBIO, "fdclose", 0);
487 sc->flags &= ~FDF_WMOTOROFF;
488 wakeup(fdmotoroff);
489 }
490 sc->openpart = -1;
491 splx(s);
492 return(0);
493 }
494
495 int
496 fdioctl(dev, cmd, addr, flag, p)
497 dev_t dev;
498 u_long cmd;
499 caddr_t addr;
500 int flag;
501 struct proc *p;
502 {
503 struct fd_softc *sc;
504 int error, wlab;
505
506 sc = getsoftc(fd_cd, FDUNIT(dev));
507
508 if ((sc->flags & FDF_HAVELABEL) == 0)
509 return(EBADF);
510
511 switch (cmd) {
512 case DIOCSBAD:
513 return(EINVAL);
514 case DIOCSRETRIES:
515 if (*(int *)addr < 0)
516 return(EINVAL);
517 sc->retries = *(int *)addr;
518 return(0);
519 case DIOCSSTEP:
520 if (*(int *)addr < FDSTEPDELAY)
521 return(EINVAL);
522 sc->dkdev.dk_label->d_trkseek = sc->stepdelay = *(int *)addr;
523 return(0);
524 case DIOCGDINFO:
525 *(struct disklabel *)addr = *(sc->dkdev.dk_label);
526 return(0);
527 case DIOCGPART:
528 ((struct partinfo *)addr)->disklab = sc->dkdev.dk_label;
529 ((struct partinfo *)addr)->part =
530 &sc->dkdev.dk_label->d_partitions[FDPART(dev)];
531 return(0);
532 case DIOCSDINFO:
533 if ((flag & FWRITE) == 0)
534 return(EBADF);
535 return(fdsetdisklabel(sc, (struct disklabel *)addr));
536 case DIOCWDINFO:
537 if ((flag & FWRITE) == 0)
538 return(EBADF);
539 if ((error = fdsetdisklabel(sc, (struct disklabel *)addr)) != 0)
540 return(error);
541 wlab = sc->wlabel;
542 sc->wlabel = 1;
543 error = fdputdisklabel(sc, dev);
544 sc->wlabel = wlab;
545 return(error);
546 case DIOCWLABEL:
547 if ((flag & FWRITE) == 0)
548 return(EBADF);
549 sc->wlabel = *(int *)addr;
550 return(0);
551 default:
552 return(ENOTTY);
553 }
554 }
555
556 /*
557 * no dumps to floppy disks thank you.
558 */
559 int
560 fdsize(dev)
561 dev_t dev;
562 {
563 return(-1);
564 }
565
566 int
567 fdread(dev, uio, flags)
568 dev_t dev;
569 struct uio *uio;
570 int flags;
571 {
572 return (physio(fdstrategy, NULL, dev, B_READ, fdminphys, uio));
573 }
574
575 int
576 fdwrite(dev, uio, flags)
577 dev_t dev;
578 struct uio *uio;
579 int flags;
580 {
581 return (physio(fdstrategy, NULL, dev, B_WRITE, fdminphys, uio));
582 }
583
584
585 void
586 fdintr(flag)
587 int flag;
588 {
589 int s;
590
591 s = splbio();
592 if (fdc_indma)
593 fddmadone(fdc_indma, 0);
594 splx(s);
595 }
596
597 void
598 fdstrategy(bp)
599 struct buf *bp;
600 {
601 struct disklabel *lp;
602 struct fd_softc *sc;
603 struct buf *dp;
604 int unit, part, s;
605
606 unit = FDUNIT(bp->b_dev);
607 part = FDPART(bp->b_dev);
608 sc = getsoftc(fd_cd, unit);
609
610 #ifdef FDDEBUG
611 printf("fdstrategy: 0x%x\n", bp);
612 #endif
613 /*
614 * check for valid partition and bounds
615 */
616 lp = sc->dkdev.dk_label;
617 if ((sc->flags & FDF_HAVELABEL) == 0) {
618 bp->b_error = EIO;
619 goto bad;
620 }
621 if (bounds_check_with_label(bp, lp, sc->wlabel) <= 0)
622 goto done;
623
624 /*
625 * trans count of zero or bounds check indicates io is done
626 * we are done.
627 */
628 if (bp->b_bcount == 0)
629 goto done;
630
631 /*
632 * queue the buf and kick the low level code
633 */
634 s = splbio();
635 dp = &sc->bufq;
636 disksort(dp, bp);
637 fdstart(sc);
638 splx(s);
639 return;
640 bad:
641 bp->b_flags |= B_ERROR;
642 done:
643 bp->b_resid = bp->b_bcount;
644 biodone(bp);
645 }
646
647 /*
648 * make sure disk is loaded and label is up-to-date.
649 */
650 int
651 fdloaddisk(sc)
652 struct fd_softc *sc;
653 {
654 /*
655 * if diskchange is low step drive to 0 then up one then to zero.
656 */
657 fdsetpos(sc, 0, 0);
658 if (FDTESTC(FDB_CHANGED)) {
659 sc->cachetrk = -1; /* invalidate the cache */
660 sc->flags &= ~FDF_HAVELABEL;
661 fdsetpos(sc, FDNHEADS, 0);
662 fdsetpos(sc, 0, 0);
663 if (FDTESTC(FDB_CHANGED)) {
664 fdmotoroff(sc);
665 return(ENXIO);
666 }
667 }
668 fdmotoroff(sc);
669 sc->type = fdcgetfdtype(sc->hwunit);
670 if (sc->type == NULL)
671 return(ENXIO);
672 #ifdef not_yet
673 if (sc->openpart == FDMSDOSPART)
674 sc->nsectors = sc->type->msdos_nsectors;
675 else
676 #endif
677 sc->nsectors = sc->type->amiga_nsectors;
678 return(0);
679 }
680
681 /*
682 * read disk label, if present otherwise create one
683 * return a new label if raw part and none found, otherwise err.
684 */
685 int
686 fdgetdisklabel(sc, dev)
687 struct fd_softc *sc;
688 dev_t dev;
689 {
690 struct disklabel *lp, *dlp;
691 struct cpu_disklabel *clp;
692 struct buf *bp;
693 int error, part;
694
695 if (sc->flags & FDF_HAVELABEL)
696 return(0);
697 #ifdef FDDEBUG
698 printf("fdgetdisklabel()\n");
699 #endif
700 part = FDPART(dev);
701 lp = sc->dkdev.dk_label;
702 clp = sc->dkdev.dk_cpulabel;
703 bzero(lp, sizeof(struct disklabel));
704 bzero(clp, sizeof(struct cpu_disklabel));
705
706 lp->d_secsize = FDSECSIZE;
707 lp->d_ntracks = FDNHEADS;
708 lp->d_ncylinders = sc->type->ncylinders;
709 lp->d_nsectors = sc->nsectors;
710 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
711 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
712 lp->d_npartitions = part + 1;
713 lp->d_partitions[part].p_size = lp->d_secperunit;
714 lp->d_partitions[part].p_fstype = FS_UNUSED;
715 lp->d_partitions[part].p_fsize = 1024;
716 lp->d_partitions[part].p_frag = 8;
717 lp->d_partitions[part].p_cpg = 2; /* for adosfs: reserved blks */
718
719 sc->flags |= FDF_HAVELABEL;
720
721 bp = (void *)geteblk((int)lp->d_secsize);
722 bp->b_dev = dev;
723 bp->b_blkno = 0;
724 bp->b_cylin = 0;
725 bp->b_bcount = FDSECSIZE;
726 bp->b_flags = B_BUSY | B_READ;
727 fdstrategy(bp);
728 if ((error = biowait(bp)) != 0)
729 goto nolabel;
730 dlp = (struct disklabel *)(bp->b_data + LABELOFFSET);
731 if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC ||
732 dkcksum(dlp)) {
733 error = EINVAL;
734 goto nolabel;
735 }
736 bcopy(dlp, lp, sizeof(struct disklabel));
737 if (lp->d_trkseek > FDSTEPDELAY)
738 sc->stepdelay = lp->d_trkseek;
739 brelse(bp);
740 return(0);
741 nolabel:
742 bzero(lp, sizeof(struct disklabel));
743 lp->d_secsize = FDSECSIZE;
744 lp->d_ntracks = FDNHEADS;
745 lp->d_ncylinders = sc->type->ncylinders;
746 lp->d_nsectors = sc->nsectors;
747 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
748 lp->d_type = DTYPE_FLOPPY;
749 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
750 lp->d_rpm = 300; /* good guess I suppose. */
751 lp->d_interleave = 1; /* should change when adding msdos */
752 sc->stepdelay = lp->d_trkseek = FDSTEPDELAY;
753 lp->d_bbsize = 0;
754 lp->d_sbsize = 0;
755 lp->d_partitions[part].p_size = lp->d_secperunit;
756 lp->d_partitions[part].p_fstype = FS_UNUSED;
757 lp->d_partitions[part].p_fsize = 1024;
758 lp->d_partitions[part].p_frag = 8;
759 lp->d_partitions[part].p_cpg = 2; /* adosfs: reserved blocks */
760 lp->d_npartitions = part + 1;
761 lp->d_magic = lp->d_magic2 = DISKMAGIC;
762 lp->d_checksum = dkcksum(lp);
763 brelse(bp);
764 return(0);
765 }
766
767 /*
768 * set the incore copy of this units disklabel
769 */
770 int
771 fdsetdisklabel(sc, lp)
772 struct fd_softc *sc;
773 struct disklabel *lp;
774 {
775 struct disklabel *clp;
776 struct partition *pp;
777
778 /*
779 * must have at least opened raw unit to fetch the
780 * raw_part stuff.
781 */
782 if ((sc->flags & FDF_HAVELABEL) == 0)
783 return(EINVAL);
784 clp = sc->dkdev.dk_label;
785 /*
786 * make sure things check out and we only have one valid
787 * partition
788 */
789 #ifdef FDDEBUG
790 printf("fdsetdisklabel\n");
791 #endif
792 if (lp->d_secsize != FDSECSIZE ||
793 lp->d_nsectors != clp->d_nsectors ||
794 lp->d_ntracks != FDNHEADS ||
795 lp->d_ncylinders != clp->d_ncylinders ||
796 lp->d_secpercyl != clp->d_secpercyl ||
797 lp->d_secperunit != clp->d_secperunit ||
798 lp->d_magic != DISKMAGIC ||
799 lp->d_magic2 != DISKMAGIC ||
800 lp->d_npartitions == 0 ||
801 lp->d_npartitions > FDMAXPARTS ||
802 (lp->d_partitions[0].p_offset && lp->d_partitions[1].p_offset) ||
803 dkcksum(lp))
804 return(EINVAL);
805 /*
806 * if any partitions are present make sure they
807 * represent the currently open type
808 */
809 if ((pp = &lp->d_partitions[0])->p_size) {
810 if ((pp = &lp->d_partitions[1])->p_size == 0)
811 goto done;
812 else if (sc->openpart != 1)
813 return(EINVAL);
814 } else if (sc->openpart != 0)
815 return(EINVAL);
816 /*
817 * make sure selected partition is within bounds
818 * XXX on the second check, its to handle a bug in
819 * XXX the cluster routines as they require mutliples
820 * XXX of CLBYTES currently
821 */
822 if ((pp->p_offset + pp->p_size >= lp->d_secperunit) ||
823 (pp->p_frag * pp->p_fsize % CLBYTES))
824 return(EINVAL);
825 done:
826 bcopy(lp, clp, sizeof(struct disklabel));
827 return(0);
828 }
829
830 /*
831 * write out the incore copy of this units disklabel
832 */
833 int
834 fdputdisklabel(sc, dev)
835 struct fd_softc *sc;
836 dev_t dev;
837 {
838 struct disklabel *lp, *dlp;
839 struct buf *bp;
840 int error;
841
842 if ((sc->flags & FDF_HAVELABEL) == 0)
843 return(EBADF);
844 #ifdef FDDEBUG
845 printf("fdputdisklabel\n");
846 #endif
847 /*
848 * get buf and read in sector 0
849 */
850 lp = sc->dkdev.dk_label;
851 bp = (void *)geteblk((int)lp->d_secsize);
852 bp->b_dev = FDMAKEDEV(major(dev), FDUNIT(dev), RAW_PART);
853 bp->b_blkno = 0;
854 bp->b_cylin = 0;
855 bp->b_bcount = FDSECSIZE;
856 bp->b_flags = B_BUSY | B_READ;
857 fdstrategy(bp);
858 if ((error = biowait(bp)) != 0)
859 goto done;
860 /*
861 * copy disklabel to buf and write it out syncronous
862 */
863 dlp = (struct disklabel *)(bp->b_data + LABELOFFSET);
864 bcopy(lp, dlp, sizeof(struct disklabel));
865 bp->b_blkno = 0;
866 bp->b_cylin = 0;
867 bp->b_flags = B_WRITE;
868 fdstrategy(bp);
869 error = biowait(bp);
870 done:
871 brelse(bp);
872 return(error);
873 }
874
875 /*
876 * figure out drive type or NULL if none.
877 */
878 struct fdtype *
879 fdcgetfdtype(unit)
880 int unit;
881 {
882 struct fdtype *ftp;
883 u_long id, idb;
884 int cnt, umask;
885
886 id = 0;
887 umask = 1 << (3 + unit);
888
889 FDDESELECT(FDCUNITMASK);
890
891 FDSETMOTOR(1);
892 delay(1);
893 FDSELECT(umask);
894 delay(1);
895 FDDESELECT(umask);
896
897 FDSETMOTOR(0);
898 delay(1);
899 FDSELECT(umask);
900 delay(1);
901 FDDESELECT(umask);
902
903 for (idb = 0x80000000; idb; idb >>= 1) {
904 FDSELECT(umask);
905 delay(1);
906 if (FDTESTC(FDB_READY) == 0)
907 id |= idb;
908 FDDESELECT(umask);
909 delay(1);
910 }
911 #ifdef FDDEBUG
912 printf("fdcgettype unit %d id 0x%x\n", unit, id);
913 #endif
914
915 for (cnt = 0, ftp = fdtype; cnt < nfdtype; ftp++, cnt++)
916 if (ftp->driveid == id)
917 return(ftp);
918 /*
919 * 3.5dd's at unit 0 do not always return id.
920 */
921 if (unit == 0)
922 return(fdtype);
923 return(NULL);
924 }
925
926 /*
927 * turn motor off if possible otherwise mark as needed and will be done
928 * later.
929 */
930 void
931 fdmotoroff(arg)
932 void *arg;
933 {
934 struct fd_softc *sc;
935 int s;
936
937 sc = arg;
938 s = splbio();
939
940 #ifdef FDDEBUG
941 printf("fdmotoroff: unit %d\n", sc->hwunit);
942 #endif
943 if ((sc->flags & FDF_MOTORON) == 0)
944 goto done;
945 /*
946 * if we have a timeout on a dma operation let fddmadone()
947 * deal with it.
948 */
949 if (fdc_indma == sc) {
950 fddmadone(sc, 1);
951 goto done;
952 }
953 #ifdef FDDEBUG
954 printf(" motor was on, turning off\n");
955 #endif
956
957 /*
958 * flush cache if needed
959 */
960 if (sc->flags & FDF_DIRTY) {
961 sc->flags |= FDF_JUSTFLUSH | FDF_MOTOROFF;
962 #ifdef FDDEBUG
963 printf(" flushing dirty buffer first\n");
964 #endif
965 /*
966 * if dma'ing done for now, fddone() will call us again
967 */
968 if (fdc_indma)
969 goto done;
970 fddmastart(sc, sc->cachetrk);
971 goto done;
972 }
973
974 /*
975 * if controller is busy just schedule us to be called back
976 */
977 if (fdc_indma) {
978 /*
979 * someone else has the controller now
980 * just set flag and let fddone() call us again.
981 */
982 sc->flags |= FDF_MOTOROFF;
983 goto done;
984 }
985
986 #ifdef FDDEBUG
987 printf(" hw turing unit off\n");
988 #endif
989
990 sc->flags &= ~(FDF_MOTORON | FDF_MOTOROFF);
991 FDDESELECT(FDCUNITMASK);
992 FDSETMOTOR(0);
993 delay(1);
994 FDSELECT(sc->unitmask);
995 delay(4);
996 FDDESELECT(sc->unitmask);
997 delay(1);
998 if (sc->flags & FDF_WMOTOROFF)
999 wakeup(fdmotoroff);
1000 done:
1001 splx(s);
1002 }
1003
1004 /*
1005 * select drive seek to track exit with motor on.
1006 * fdsetpos(x, 0, 0) does calibrates the drive.
1007 */
1008 void
1009 fdsetpos(sc, trk, towrite)
1010 struct fd_softc *sc;
1011 int trk, towrite;
1012 {
1013 int nstep, sdir, ondly, ncyl, nside;
1014
1015 FDDESELECT(FDCUNITMASK);
1016 FDSETMOTOR(1);
1017 delay(1);
1018 FDSELECT(sc->unitmask);
1019 delay(1);
1020 if ((sc->flags & FDF_MOTORON) == 0) {
1021 ondly = 0;
1022 while (FDTESTC(FDB_READY) == 0) {
1023 delay(1000);
1024 if (++ondly >= 1000)
1025 break;
1026 }
1027 }
1028 sc->flags |= FDF_MOTORON;
1029
1030 ncyl = trk / FDNHEADS;
1031 nside = trk % FDNHEADS;
1032
1033 if (sc->curcyl == ncyl && fdc_side == nside)
1034 return;
1035
1036 if (towrite)
1037 sc->flags |= FDF_WRITEWAIT;
1038
1039 #ifdef FDDEBUG
1040 printf("fdsetpos: cyl %d head %d towrite %d\n", trk / FDNHEADS,
1041 trk % FDNHEADS, towrite);
1042 #endif
1043 nstep = ncyl - sc->curcyl;
1044 if (nstep) {
1045 /*
1046 * figure direction
1047 */
1048 if (nstep > 0 && ncyl != 0) {
1049 sdir = FDSTEPIN;
1050 FDSETDIR(1);
1051 } else {
1052 nstep = -nstep;
1053 sdir = FDSTEPOUT;
1054 FDSETDIR(0);
1055 }
1056 if (ncyl == 0) {
1057 /*
1058 * either just want cylinder 0 or doing
1059 * a calibrate.
1060 */
1061 nstep = 256;
1062 while (FDTESTC(FDB_CYLZERO) == 0 && nstep--) {
1063 FDSTEP;
1064 delay(sc->stepdelay);
1065 }
1066 if (nstep < 0)
1067 sc->flags |= FDF_NOTRACK0;
1068 } else {
1069 /*
1070 * step the needed amount amount.
1071 */
1072 while (nstep--) {
1073 FDSTEP;
1074 delay(sc->stepdelay);
1075 }
1076 }
1077 /*
1078 * if switched directions
1079 * allow drive to settle.
1080 */
1081 if (sc->pstepdir != sdir)
1082 delay(FDSETTLEDELAY);
1083 sc->pstepdir = sdir;
1084 sc->curcyl = ncyl;
1085 }
1086 if (nside == fdc_side)
1087 return;
1088 /*
1089 * select side
1090 */
1091 fdc_side = nside;
1092 FDSETHEAD(nside);
1093 delay(FDPRESIDEDELAY);
1094 }
1095
1096 void
1097 fdselunit(sc)
1098 struct fd_softc *sc;
1099 {
1100 FDDESELECT(FDCUNITMASK); /* deselect all */
1101 FDSETMOTOR(sc->flags & FDF_MOTORON); /* set motor to unit's state */
1102 delay(1);
1103 FDSELECT(sc->unitmask); /* select unit */
1104 delay(1);
1105 }
1106
1107 /*
1108 * process next buf on device queue.
1109 * normall sequence of events:
1110 * fdstart() -> fddmastart();
1111 * fdintr() -> fddmadone() -> fddone();
1112 * if the track is in the cache then fdstart() will short-circuit
1113 * to fddone() else if the track cache is dirty it will flush. If
1114 * the buf is not an entire track it will cache the requested track.
1115 */
1116 void
1117 fdstart(sc)
1118 struct fd_softc *sc;
1119 {
1120 int trk, error, write;
1121 struct buf *bp, *dp;
1122
1123 #ifdef FDDEBUG
1124 printf("fdstart: unit %d\n", sc->hwunit);
1125 #endif
1126
1127 /*
1128 * if dma'ing just return. we must have been called from fdstartegy.
1129 */
1130 if (fdc_indma)
1131 return;
1132
1133 /*
1134 * get next buf if there.
1135 */
1136 dp = &sc->bufq;
1137 if ((bp = dp->b_actf) == NULL) {
1138 #ifdef FDDEBUG
1139 printf(" nothing to do\n");
1140 #endif
1141 return;
1142 }
1143
1144 /*
1145 * Mark us as busy now, in case fddone() gets called in one
1146 * of the cases below.
1147 */
1148 disk_busy(&sc->dkdev);
1149
1150 /*
1151 * make sure same disk is loaded
1152 */
1153 fdselunit(sc);
1154 if (FDTESTC(FDB_CHANGED)) {
1155 /*
1156 * disk missing, invalidate all future io on
1157 * this unit until re-open()'ed also invalidate
1158 * all current io
1159 */
1160 #ifdef FDDEBUG
1161 printf(" disk was removed invalidating all io\n");
1162 #endif
1163 sc->flags &= ~FDF_HAVELABEL;
1164 for (;;) {
1165 bp->b_flags |= B_ERROR;
1166 bp->b_error = EIO;
1167 if (bp->b_actf == NULL)
1168 break;
1169 biodone(bp);
1170 bp = bp->b_actf;
1171 }
1172 /*
1173 * do fddone() on last buf to allow other units to start.
1174 */
1175 dp->b_actf = bp;
1176 fddone(sc);
1177 return;
1178 }
1179
1180 /*
1181 * we have a valid buf, setup our local version
1182 * we use this count to allow reading over multiple tracks.
1183 * into a single buffer
1184 */
1185 dp->b_bcount = bp->b_bcount;
1186 dp->b_blkno = bp->b_blkno;
1187 dp->b_data = bp->b_data;
1188 dp->b_flags = bp->b_flags;
1189 dp->b_resid = 0;
1190
1191 if (bp->b_flags & B_READ)
1192 write = 0;
1193 else if (FDTESTC(FDB_PROTECT) == 0)
1194 write = 1;
1195 else {
1196 error = EPERM;
1197 goto bad;
1198 }
1199
1200 /*
1201 * figure trk given blkno
1202 */
1203 trk = bp->b_blkno / sc->nsectors;
1204
1205 /*
1206 * check to see if same as currently cached track
1207 * if so we need to do no dma read.
1208 */
1209 if (trk == sc->cachetrk) {
1210 fddone(sc);
1211 return;
1212 }
1213
1214 /*
1215 * if we will be overwriting the entire cache, don't bother to
1216 * fetch it.
1217 */
1218 if (bp->b_bcount == (sc->nsectors * FDSECSIZE) && write &&
1219 bp->b_blkno % sc->nsectors == 0) {
1220 if (sc->flags & FDF_DIRTY)
1221 sc->flags |= FDF_JUSTFLUSH;
1222 else {
1223 sc->cachetrk = trk;
1224 fddone(sc);
1225 return;
1226 }
1227 }
1228
1229 /*
1230 * start dma read of `trk'
1231 */
1232 fddmastart(sc, trk);
1233 return;
1234 bad:
1235 bp->b_flags |= B_ERROR;
1236 bp->b_error = error;
1237 fddone(sc);
1238 }
1239
1240 /*
1241 * continue a started operation on next track. always begin at
1242 * sector 0 on the next track.
1243 */
1244 void
1245 fdcont(sc)
1246 struct fd_softc *sc;
1247 {
1248 struct buf *dp, *bp;
1249 int trk, write;
1250
1251 dp = &sc->bufq;
1252 bp = dp->b_actf;
1253 dp->b_data += (dp->b_bcount - bp->b_resid);
1254 dp->b_blkno += (dp->b_bcount - bp->b_resid) / FDSECSIZE;
1255 dp->b_bcount = bp->b_resid;
1256
1257 /*
1258 * figure trk given blkno
1259 */
1260 trk = dp->b_blkno / sc->nsectors;
1261 #ifdef DEBUG
1262 if (trk != sc->cachetrk + 1 || dp->b_blkno % sc->nsectors != 0)
1263 panic("fdcont: confused");
1264 #endif
1265 if (dp->b_flags & B_READ)
1266 write = 0;
1267 else
1268 write = 1;
1269 /*
1270 * if we will be overwriting the entire cache, don't bother to
1271 * fetch it.
1272 */
1273 if (dp->b_bcount == (sc->nsectors * FDSECSIZE) && write) {
1274 if (sc->flags & FDF_DIRTY)
1275 sc->flags |= FDF_JUSTFLUSH;
1276 else {
1277 sc->cachetrk = trk;
1278 fddone(sc);
1279 return;
1280 }
1281 }
1282 /*
1283 * start dma read of `trk'
1284 */
1285 fddmastart(sc, trk);
1286 return;
1287 }
1288
1289 void
1290 fddmastart(sc, trk)
1291 struct fd_softc *sc;
1292 int trk;
1293 {
1294 int adkmask, ndmaw, write, dmatrk;
1295
1296 #ifdef FDDEBUG
1297 printf("fddmastart: unit %d cyl %d head %d", sc->hwunit,
1298 trk / FDNHEADS, trk % FDNHEADS);
1299 #endif
1300 /*
1301 * flush the cached track if dirty else read requested track.
1302 */
1303 if (sc->flags & FDF_DIRTY) {
1304 fdcachetoraw(sc);
1305 ndmaw = sc->type->nwritew;
1306 dmatrk = sc->cachetrk;
1307 write = 1;
1308 } else {
1309 ndmaw = sc->type->nreadw;
1310 dmatrk = trk;
1311 write = 0;
1312 }
1313
1314 #ifdef FDDEBUG
1315 printf(" %s", write ? " flushing cache\n" : " loading cache\n");
1316 #endif
1317 sc->cachetrk = trk;
1318 fdc_indma = sc;
1319 fdsetpos(sc, dmatrk, write);
1320
1321 /*
1322 * setup dma stuff
1323 */
1324 if (write == 0) {
1325 custom.adkcon = ADKF_MSBSYNC;
1326 custom.adkcon = ADKF_SETCLR | ADKF_WORDSYNC | ADKF_FAST;
1327 custom.dsksync = FDMFMSYNC;
1328 } else {
1329 custom.adkcon = ADKF_PRECOMP1 | ADKF_PRECOMP0 | ADKF_WORDSYNC |
1330 ADKF_MSBSYNC;
1331 adkmask = ADKF_SETCLR | ADKF_FAST | ADKF_MFMPREC;
1332 if (dmatrk >= sc->type->precomp[0])
1333 adkmask |= ADKF_PRECOMP0;
1334 if (dmatrk >= sc->type->precomp[1])
1335 adkmask |= ADKF_PRECOMP1;
1336 custom.adkcon = adkmask;
1337 }
1338 custom.dskpt = (u_char *)kvtop(fdc_dmap);
1339 FDDMASTART(ndmaw, write);
1340
1341 #ifdef FDDEBUG
1342 printf(" dma started\n");
1343 #endif
1344 }
1345
1346 /*
1347 * recalibrate the drive
1348 */
1349 void
1350 fdcalibrate(arg)
1351 void *arg;
1352 {
1353 struct fd_softc *sc;
1354 static int loopcnt;
1355
1356 sc = arg;
1357
1358 if (loopcnt == 0) {
1359 /*
1360 * seek cyl 0
1361 */
1362 fdc_indma = sc;
1363 sc->stepdelay += 900;
1364 if (sc->cachetrk > 1)
1365 fdsetpos(sc, sc->cachetrk % FDNHEADS, 0);
1366 sc->stepdelay -= 900;
1367 }
1368 if (loopcnt++ & 1)
1369 fdsetpos(sc, sc->cachetrk, 0);
1370 else
1371 fdsetpos(sc, sc->cachetrk + FDNHEADS, 0);
1372 /*
1373 * trk++, trk, trk++, trk, trk++, trk, trk++, trk and dma
1374 */
1375 if (loopcnt < 8)
1376 timeout(fdcalibrate, sc, hz / 8);
1377 else {
1378 loopcnt = 0;
1379 fdc_indma = NULL;
1380 timeout(fdmotoroff, sc, 3 * hz / 2);
1381 fddmastart(sc, sc->cachetrk);
1382 }
1383 }
1384
1385 void
1386 fddmadone(sc, timeo)
1387 struct fd_softc *sc;
1388 int timeo;
1389 {
1390 #ifdef FDDEBUG
1391 printf("fddmadone: unit %d, timeo %d\n", sc->hwunit, timeo);
1392 #endif
1393 fdc_indma = NULL;
1394 untimeout(fdmotoroff, sc);
1395 FDDMASTOP;
1396
1397 /*
1398 * guarantee the drive has been at current head and cyl
1399 * for at least FDWRITEDELAY after a write.
1400 */
1401 if (sc->flags & FDF_WRITEWAIT) {
1402 delay(FDWRITEDELAY);
1403 sc->flags &= ~FDF_WRITEWAIT;
1404 }
1405
1406 if ((sc->flags & FDF_MOTOROFF) == 0) {
1407 /*
1408 * motor runs for 1.5 seconds after last dma
1409 */
1410 timeout(fdmotoroff, sc, 3 * hz / 2);
1411 }
1412 if (sc->flags & FDF_DIRTY) {
1413 /*
1414 * if buffer dirty, the last dma cleaned it
1415 */
1416 sc->flags &= ~FDF_DIRTY;
1417 if (timeo)
1418 printf("%s: write of track cache timed out.\n",
1419 sc->sc_dv.dv_xname);
1420 if (sc->flags & FDF_JUSTFLUSH) {
1421 sc->flags &= ~FDF_JUSTFLUSH;
1422 /*
1423 * we are done dma'ing
1424 */
1425 fddone(sc);
1426 return;
1427 }
1428 /*
1429 * load the cache
1430 */
1431 fddmastart(sc, sc->cachetrk);
1432 return;
1433 }
1434 #ifdef FDDEBUG
1435 else if (sc->flags & FDF_MOTOROFF)
1436 panic("fddmadone: FDF_MOTOROFF with no FDF_DIRTY");
1437 #endif
1438
1439 /*
1440 * cache loaded decode it into cache buffer
1441 */
1442 if (timeo == 0 && fdrawtocache(sc) == 0)
1443 sc->retried = 0;
1444 else {
1445 #ifdef FDDEBUG
1446 if (timeo)
1447 printf("%s: fddmadone: cache load timed out.\n",
1448 sc->sc_dv.dv_xname);
1449 #endif
1450 if (sc->retried >= sc->retries) {
1451 sc->retried = 0;
1452 sc->cachetrk = -1;
1453 } else {
1454 sc->retried++;
1455 /*
1456 * this will be restarted at end of calibrate loop.
1457 */
1458 untimeout(fdmotoroff, sc);
1459 fdcalibrate(sc);
1460 return;
1461 }
1462 }
1463 fddone(sc);
1464 }
1465
1466 void
1467 fddone(sc)
1468 struct fd_softc *sc;
1469 {
1470 struct buf *dp, *bp;
1471 char *data;
1472 int sz;
1473
1474 #ifdef FDDEBUG
1475 printf("fddone: unit %d\n", sc->hwunit);
1476 #endif
1477 /*
1478 * check to see if unit is just flushing the cache,
1479 * that is we have no io queued.
1480 */
1481 if (sc->flags & FDF_MOTOROFF)
1482 goto nobuf;
1483
1484 dp = &sc->bufq;
1485 if ((bp = dp->b_actf) == NULL)
1486 panic ("fddone");
1487 /*
1488 * check for an error that may have occured
1489 * while getting the track.
1490 */
1491 if (sc->cachetrk == -1) {
1492 sc->retried = 0;
1493 bp->b_flags |= B_ERROR;
1494 bp->b_error = EIO;
1495 } else if ((bp->b_flags & B_ERROR) == 0) {
1496 data = sc->cachep;
1497 /*
1498 * get offset of data in track cache and limit
1499 * the copy size to not exceed the cache's end.
1500 */
1501 data += (dp->b_blkno % sc->nsectors) * FDSECSIZE;
1502 sz = sc->nsectors - dp->b_blkno % sc->nsectors;
1503 sz *= FDSECSIZE;
1504 sz = min(dp->b_bcount, sz);
1505 if (bp->b_flags & B_READ)
1506 bcopy(data, dp->b_data, sz);
1507 else {
1508 bcopy(dp->b_data, data, sz);
1509 sc->flags |= FDF_DIRTY;
1510 }
1511 bp->b_resid = dp->b_bcount - sz;
1512 if (bp->b_resid == 0) {
1513 bp->b_error = 0;
1514 } else {
1515 /*
1516 * not done yet need to read next track
1517 */
1518 fdcont(sc);
1519 return;
1520 }
1521 }
1522 /*
1523 * remove from queue.
1524 */
1525 dp->b_actf = bp->b_actf;
1526
1527 disk_unbusy(&sc->dkdev, (bp->b_bcount - bp->b_resid));
1528
1529 biodone(bp);
1530 nobuf:
1531 fdfindwork(sc->sc_dv.dv_unit);
1532 }
1533
1534 void
1535 fdfindwork(unit)
1536 int unit;
1537 {
1538 struct fd_softc *ssc, *sc;
1539 int i, last;
1540
1541 /*
1542 * first see if we have any fdopen()'s waiting
1543 */
1544 if (fdc_wantwakeup) {
1545 wakeup(fdopen);
1546 fdc_wantwakeup--;
1547 return;
1548 }
1549
1550 /*
1551 * start next available unit, linear search from the next unit
1552 * wrapping and finally this unit.
1553 */
1554 last = 0;
1555 ssc = NULL;
1556 for (i = unit + 1; last == 0; i++) {
1557 if (i == unit)
1558 last = 1;
1559 if (i >= fd_cd.cd_ndevs) {
1560 i = -1;
1561 continue;
1562 }
1563 if ((sc = fd_cd.cd_devs[i]) == NULL)
1564 continue;
1565
1566 /*
1567 * if unit has requested to be turned off
1568 * and it has no buf's queued do it now
1569 */
1570 if (sc->flags & FDF_MOTOROFF) {
1571 if (sc->bufq.b_actf == NULL)
1572 fdmotoroff(sc);
1573 else {
1574 /*
1575 * we gained a buf request while
1576 * we waited, forget the motoroff
1577 */
1578 sc->flags &= ~FDF_MOTOROFF;
1579 }
1580 /*
1581 * if we now have dma unit must have needed
1582 * flushing, quit
1583 */
1584 if (fdc_indma)
1585 return;
1586 }
1587 /*
1588 * if we have no start unit and the current unit has
1589 * io waiting choose this unit to start.
1590 */
1591 if (ssc == NULL && sc->bufq.b_actf)
1592 ssc = sc;
1593 }
1594 if (ssc)
1595 fdstart(ssc);
1596 }
1597
1598 /*
1599 * min byte count to whats left of the track in question
1600 */
1601 void
1602 fdminphys(bp)
1603 struct buf *bp;
1604 {
1605 struct fd_softc *sc;
1606 int trk, sec, toff, tsz;
1607
1608 if ((sc = getsoftc(fd_cd, FDUNIT(bp->b_dev))) == NULL)
1609 panic("fdminphys: couldn't get softc");
1610
1611 trk = bp->b_blkno / sc->nsectors;
1612 sec = bp->b_blkno % sc->nsectors;
1613
1614 toff = sec * FDSECSIZE;
1615 tsz = sc->nsectors * FDSECSIZE;
1616 #ifdef FDDEBUG
1617 printf("fdminphys: before %d", bp->b_bcount);
1618 #endif
1619 bp->b_bcount = min(bp->b_bcount, tsz - toff);
1620 #ifdef FDDEBUG
1621 printf(" after %d\n", bp->b_bcount);
1622 #endif
1623 minphys(bp);
1624 }
1625
1626 /*
1627 * encode the track cache into raw MFM ready for dma
1628 * when we go to multiple disk formats, this will call type dependent
1629 * functions
1630 */
1631 void
1632 fdcachetoraw(sc)
1633 struct fd_softc *sc;
1634 {
1635 static u_long mfmnull[4];
1636 u_long *rp, *crp, *dp, hcksum, dcksum, info, zero;
1637 int sec, i;
1638
1639 rp = fdc_dmap;
1640
1641 /*
1642 * not yet one sector (- 1 long) gap.
1643 * for now use previous drivers values
1644 */
1645 for (i = 0; i < sc->type->gap; i++)
1646 *rp++ = 0xaaaaaaaa;
1647 /*
1648 * process sectors
1649 */
1650 dp = sc->cachep;
1651 zero = 0;
1652 info = 0xff000000 | (sc->cachetrk << 16) | sc->nsectors;
1653 for (sec = 0; sec < sc->nsectors; sec++, info += (1 << 8) - 1) {
1654 hcksum = dcksum = 0;
1655 /*
1656 * sector format
1657 * offset description
1658 *-----------------------------------
1659 * 0 null
1660 * 1 sync
1661 * oddbits evenbits
1662 *----------------------
1663 * 2 3 [0xff]b [trk]b [sec]b [togap]b
1664 * 4-7 8-11 null
1665 * 12 13 header cksum [2-11]
1666 * 14 15 data cksum [16-271]
1667 * 16-143 144-271 data
1668 */
1669 *rp = 0xaaaaaaaa;
1670 if (*(rp - 1) & 0x1)
1671 *rp &= 0x7fffffff; /* clock bit correction */
1672 rp++;
1673 *rp++ = (FDMFMSYNC << 16) | FDMFMSYNC;
1674 rp = mfmblkencode(&info, rp, &hcksum, 1);
1675 rp = mfmblkencode(mfmnull, rp, &hcksum, 4);
1676 rp = mfmblkencode(&hcksum, rp, NULL, 1);
1677
1678 crp = rp;
1679 rp = mfmblkencode(dp, rp + 2, &dcksum, FDSECLWORDS);
1680 dp += FDSECLWORDS;
1681 crp = mfmblkencode(&dcksum, crp, NULL, 1);
1682 if (*(crp - 1) & 0x1)
1683 *crp &= 0x7fffffff; /* clock bit correction */
1684 else if ((*crp & 0x40000000) == 0)
1685 *crp |= 0x80000000;
1686 }
1687 *rp = 0xaaa80000;
1688 if (*(rp - 1) & 0x1)
1689 *rp &= 0x7fffffff;
1690 }
1691
1692 u_long *
1693 fdfindsync(rp, ep)
1694 u_long *rp, *ep;
1695 {
1696 u_short *sp;
1697
1698 sp = (u_short *)rp;
1699 while ((u_long *)sp < ep && *sp != FDMFMSYNC)
1700 sp++;
1701 while ((u_long *)sp < ep && *sp == FDMFMSYNC)
1702 sp++;
1703 if ((u_long *)sp < ep)
1704 return((u_long *)sp);
1705 return(NULL);
1706 }
1707
1708 /*
1709 * decode raw MFM from dma into units track cache.
1710 * when we go to multiple disk formats, this will call type dependent
1711 * functions
1712 */
1713 int
1714 fdrawtocache(sc)
1715 struct fd_softc *sc;
1716 {
1717 u_long mfmnull[4];
1718 u_long *dp, *rp, *erp, *crp, *srp, hcksum, dcksum, info, cktmp;
1719 int cnt, doagain;
1720
1721 doagain = 1;
1722 srp = rp = fdc_dmap;
1723 erp = (u_long *)((u_short *)rp + sc->type->nreadw);
1724 cnt = 0;
1725 again:
1726 if (doagain == 0 || (rp = srp = fdfindsync(srp, erp)) == NULL) {
1727 #ifdef DIAGNOSTIC
1728 printf("%s: corrupted track (%d) data.\n",
1729 sc->sc_dv.dv_xname, sc->cachetrk);
1730 #endif
1731 return(-1);
1732 }
1733
1734 /*
1735 * process sectors
1736 */
1737 for (; cnt < sc->nsectors; cnt++) {
1738 hcksum = dcksum = 0;
1739 rp = mfmblkdecode(rp, &info, &hcksum, 1);
1740 rp = mfmblkdecode(rp, mfmnull, &hcksum, 4);
1741 rp = mfmblkdecode(rp, &cktmp, NULL, 1);
1742 if (cktmp != hcksum) {
1743 #ifdef FDDEBUG
1744 printf(" info 0x%x hchksum 0x%x trkhcksum 0x%x\n",
1745 info, hcksum, cktmp);
1746 #endif
1747 goto again;
1748 }
1749 if (((info >> 16) & 0xff) != sc->cachetrk) {
1750 #ifdef DEBUG
1751 printf("%s: incorrect track found: 0x%lx %d\n",
1752 sc->sc_dv.dv_xname, info, sc->cachetrk);
1753 #endif
1754 goto again;
1755 }
1756 #ifdef FDDEBUG
1757 printf(" info 0x%x\n", info);
1758 #endif
1759
1760 rp = mfmblkdecode(rp, &cktmp, NULL, 1);
1761 dp = sc->cachep;
1762 dp += FDSECLWORDS * ((info >> 8) & 0xff);
1763 crp = mfmblkdecode(rp, dp, &dcksum, FDSECLWORDS);
1764 if (cktmp != dcksum) {
1765 #ifdef FDDEBUG
1766 printf(" info 0x%x dchksum 0x%x trkdcksum 0x%x\n",
1767 info, dcksum, cktmp);
1768 #endif
1769 goto again;
1770 }
1771
1772 /*
1773 * if we are at gap then we can no longer be sure
1774 * of correct sync marks
1775 */
1776 if ((info && 0xff) == 1)
1777 doagain = 1;
1778 else
1779 doagain = 0;
1780 srp = rp = fdfindsync(crp, erp);
1781 }
1782 return(0);
1783 }
1784
1785 /*
1786 * encode len longwords of `dp' data in amiga mfm block format (`rp')
1787 * this format specified that the odd bits are at current pos and even
1788 * bits at len + current pos
1789 */
1790 u_long *
1791 mfmblkencode(dp, rp, cp, len)
1792 u_long *dp, *rp, *cp;
1793 int len;
1794 {
1795 u_long *sdp, *edp, d, dtmp, correct;
1796
1797 sdp = dp;
1798 edp = dp + len;
1799
1800 if (*(rp - 1) & 0x1)
1801 correct = 1;
1802 else
1803 correct = 0;
1804 /*
1805 * do odd bits
1806 */
1807 while (dp < edp) {
1808 d = (*dp >> 1) & 0x55555555; /* remove clock bits */
1809 dtmp = d ^ 0x55555555;
1810 d |= ((dtmp >> 1) | 0x80000000) & (dtmp << 1);
1811 /*
1812 * correct upper clock bit if needed
1813 */
1814 if (correct)
1815 d &= 0x7fffffff;
1816 if (d & 0x1)
1817 correct = 1;
1818 else
1819 correct = 0;
1820 /*
1821 * do checksums and store in raw buffer
1822 */
1823 if (cp)
1824 *cp ^= d;
1825 *rp++ = d;
1826 dp++;
1827 }
1828 /*
1829 * do even bits
1830 */
1831 dp = sdp;
1832 while (dp < edp) {
1833 d = *dp & 0x55555555; /* remove clock bits */
1834 dtmp = d ^ 0x55555555;
1835 d |= ((dtmp >> 1) | 0x80000000) & (dtmp << 1);
1836 /*
1837 * correct upper clock bit if needed
1838 */
1839 if (correct)
1840 d &= 0x7fffffff;
1841 if (d & 0x1)
1842 correct = 1;
1843 else
1844 correct = 0;
1845 /*
1846 * do checksums and store in raw buffer
1847 */
1848 if (cp)
1849 *cp ^= d;
1850 *rp++ = d;
1851 dp++;
1852 }
1853 if (cp)
1854 *cp &= 0x55555555;
1855 return(rp);
1856 }
1857
1858 /*
1859 * decode len longwords of `dp' data in amiga mfm block format (`rp')
1860 * this format specified that the odd bits are at current pos and even
1861 * bits at len + current pos
1862 */
1863 u_long *
1864 mfmblkdecode(rp, dp, cp, len)
1865 u_long *rp, *dp, *cp;
1866 int len;
1867 {
1868 u_long o, e;
1869 int cnt;
1870
1871 cnt = len;
1872 while (cnt--) {
1873 o = *rp;
1874 e = *(rp + len);
1875 if (cp) {
1876 *cp ^= o;
1877 *cp ^= e;
1878 }
1879 o &= 0x55555555;
1880 e &= 0x55555555;
1881 *dp++ = (o << 1) | e;
1882 rp++;
1883 }
1884 if (cp)
1885 *cp &= 0x55555555;
1886 return(rp + len);
1887 }
1888
1889 int
1890 fddump(dev, blkno, va, size)
1891 dev_t dev;
1892 daddr_t blkno;
1893 caddr_t va;
1894 size_t size;
1895 {
1896 return (EINVAL);
1897 }
1898