1 /* $NetBSD: fd.c,v 1.82 2009/03/18 17:06:41 cegger Exp $ */
4 * Copyright (c) 1994 Christian E. Hopps
5 * Copyright (c) 1996 Ezra Story
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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 Christian E. Hopps.
19 * This product includes software developed by Ezra Story.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.82 2009/03/18 17:06:41 cegger Exp $");
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/callout.h>
41 #include <sys/kernel.h>
42 #include <sys/malloc.h>
45 #include <sys/device.h>
46 #include <sys/ioctl.h>
47 #include <sys/fcntl.h>
48 #include <sys/disklabel.h>
50 #include <sys/dkbad.h>
54 #include <uvm/uvm_extern.h>
56 #include <machine/cpu.h>
57 #include <amiga/amiga/device.h>
58 #include <amiga/amiga/custom.h>
59 #include <amiga/amiga/cia.h>
60 #include <amiga/amiga/cc.h>
64 enum fdc_bits
{ FDB_CHANGED
= 2, FDB_PROTECT
, FDB_CYLZERO
, FDB_READY
};
66 * partitions in fd represent different format floppies
67 * partition a is 0 etc..
75 #define FDBBSIZE (8192)
76 #define FDSBSIZE (8192)
78 #define FDUNIT(dev) DISKUNIT(dev)
79 #define FDPART(dev) DISKPART(dev)
80 #define FDMAKEDEV(m, u, p) MAKEDISKDEV((m), (u), (p))
82 /* that's nice, but we don't want to always use this as an amiga drive
84 #define FDNHEADS (2) /* amiga drives always have 2 heads */
85 #define FDSECSIZE (512) /* amiga drives always have 512 byte sectors */
86 #define FDSECLWORDS (128)
88 #define FDSETTLEDELAY (18000) /* usec delay after seeking after switch dir */
89 #define FDSTEPDELAY (3500) /* usec delay after steping */
90 #define FDPRESIDEDELAY (1000) /* usec delay before writing can occur */
91 #define FDWRITEDELAY (1300) /* usec delay after write */
93 #define FDSTEPOUT (1) /* decrease track step */
94 #define FDSTEPIN (0) /* increase track step */
96 #define FDCUNITMASK (0x78) /* mask for all units (bits 6-3) */
98 #define FDRETRIES (2) /* default number of retries */
99 #define FDMAXUNITS (4) /* maximum number of supported units */
101 #define DISKLEN_READ (0) /* fake mask for reading */
102 #define DISKLEN_WRITE (1 << 14) /* bit for writing */
103 #define DISKLEN_DMAEN (1 << 15) /* DMA go */
104 #define DMABUFSZ ((DISKLEN_WRITE - 1) * 2) /* largest DMA possible */
106 #define FDMFMSYNC (0x4489)
107 #define FDMFMID (0x5554)
108 #define FDMFMDATA (0x5545)
109 #define FDMFMGAP1 (0x9254)
110 #define FDMFMGAP2 (0xAAAA)
111 #define FDMFMGAP3 (0x9254)
112 #define CRC16POLY (0x1021) /* (x^16) + x^12 + x^5 + x^0 */
115 * Msdos-type MFM encode/decode
117 static u_char msdecode
[128];
118 static u_char msencode
[16] =
120 0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15,
121 0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55
123 static u_short mscrctab
[256];
126 5554 aaaa aaaa aaa5 2aa4 4452 aa51
134 u_int driveid
; /* drive identification (from drive) */
135 u_int ncylinders
; /* number of cylinders on drive */
136 u_int amiga_nsectors
; /* number of sectors per amiga track */
137 u_int msdos_nsectors
; /* number of sectors per msdos track */
138 u_int nreadw
; /* number of words (short) read per track */
139 u_int nwritew
; /* number of words (short) written per track */
140 u_int gap
; /* track gap size in long words */
141 const u_int precomp
[2]; /* 1st and 2nd precomp values */
142 const char *desc
; /* description of drive type (useq) */
146 * floppy disk device data
149 struct device sc_dv
; /* generic device info; must come first */
150 struct disk dkdev
; /* generic disk info */
151 struct bufq_state
*bufq
;/* queue pending I/O operations */
152 struct buf curbuf
; /* state of current I/O operation */
153 struct callout calibrate_ch
;
154 struct callout motor_ch
;
156 void *cachep
; /* cached track data (write through) */
157 int cachetrk
; /* cahced track -1 for none */
158 int hwunit
; /* unit for amiga controlling hw */
159 int unitmask
; /* mask for cia select deslect */
160 int pstepdir
; /* previous step direction */
161 int curcyl
; /* current curcyl head positioned on */
162 int flags
; /* misc flags */
164 int stepdelay
; /* useq to delay after seek user setable */
165 int nsectors
; /* number of sectors per track */
166 int openpart
; /* which partition [ab] == [12] is open */
167 short retries
; /* number of times to retry failed io */
168 short retried
; /* number of times current io retried */
169 int bytespersec
; /* number of bytes per sector */
172 /* fd_softc->flags */
173 #define FDF_MOTORON (0x01) /* motor is running */
174 #define FDF_MOTOROFF (0x02) /* motor is waiting to be turned off */
175 #define FDF_WMOTOROFF (0x04) /* unit wants a wakeup after off */
176 #define FDF_DIRTY (0x08) /* track cache needs write */
177 #define FDF_WRITEWAIT (0x10) /* need to head select delay on next setpos */
178 #define FDF_HAVELABEL (0x20) /* label is valid */
179 #define FDF_JUSTFLUSH (0x40) /* don't bother caching track. */
180 #define FDF_NOTRACK0 (0x80) /* was not able to recalibrate drive */
185 struct fd_softc
*fdc_indma
;
194 int fdcmatch(struct device
*, struct cfdata
*, void *);
195 void fdcattach(struct device
*, struct device
*, void *);
196 int fdcprint(void *, const char *);
197 int fdmatch(struct device
*, struct cfdata
*, void *);
198 void fdattach(struct device
*, struct device
*, void *);
201 void fdidxintr(void);
202 int fdloaddisk(struct fd_softc
*);
203 void fdgetdefaultlabel(struct fd_softc
*, struct disklabel
*, int);
204 int fdgetdisklabel(struct fd_softc
*, dev_t
);
205 int fdsetdisklabel(struct fd_softc
*, struct disklabel
*);
206 int fdputdisklabel(struct fd_softc
*, dev_t
);
207 struct fdtype
* fdcgetfdtype(int);
208 void fdmotoroff(void *);
209 void fdsetpos(struct fd_softc
*, int, int);
210 void fdselunit(struct fd_softc
*);
211 void fdstart(struct fd_softc
*);
212 void fdcont(struct fd_softc
*);
213 void fddmastart(struct fd_softc
*, int);
214 void fdcalibrate(void *);
215 void fddmadone(struct fd_softc
*, int);
216 void fddone(struct fd_softc
*);
217 void fdfindwork(int);
218 void fdminphys(struct buf
*);
219 void fdcachetoraw(struct fd_softc
*);
220 void amcachetoraw(struct fd_softc
*);
221 int amrawtocache(struct fd_softc
*);
222 u_long
*fdfindsync(u_long
*, u_long
*);
223 int fdrawtocache(struct fd_softc
*);
224 void mscachetoraw(struct fd_softc
*);
225 int msrawtocache(struct fd_softc
*);
226 u_long
*mfmblkencode(u_long
*, u_long
*, u_long
*, int);
227 u_long
*mfmblkdecode(u_long
*, u_long
*, u_long
*, int);
228 u_short
*msblkdecode(u_short
*, u_char
*, int);
229 u_short
*msblkencode(u_short
*, u_char
*, int, u_short
*);
232 * read size is (nsectors + 1) * mfm secsize + gap bytes + 2 shorts
233 * write size is nsectors * mfm secsize + gap bytes + 3 shorts
234 * the extra shorts are to deal with a DMA hw bug in the controller
235 * they are probably too much (I belive the bug is 1 short on write and
236 * 3 bits on read) but there is no need to be cheap here.
238 #define MAXTRKSZ (22 * FDSECSIZE)
239 struct fdtype fdtype
[] = {
240 { 0x00000000, 80, 11, 9, 7358, 6815, 414, { 80, 161 }, "3.5dd" },
241 { 0x55555555, 40, 11, 9, 7358, 6815, 414, { 80, 161 }, "5.25dd" },
242 { 0xAAAAAAAA, 80, 22, 18, 14716, 13630, 828, { 80, 161 }, "3.5hd" }
244 int nfdtype
= sizeof(fdtype
) / sizeof(*fdtype
);
246 CFATTACH_DECL(fd
, sizeof(struct fd_softc
),
247 fdmatch
, fdattach
, NULL
, NULL
);
249 extern struct cfdriver fd_cd
;
251 dev_type_open(fdopen
);
252 dev_type_close(fdclose
);
253 dev_type_read(fdread
);
254 dev_type_write(fdwrite
);
255 dev_type_ioctl(fdioctl
);
256 dev_type_strategy(fdstrategy
);
258 const struct bdevsw fd_bdevsw
= {
259 fdopen
, fdclose
, fdstrategy
, fdioctl
, nodump
, nosize
, D_DISK
262 const struct cdevsw fd_cdevsw
= {
263 fdopen
, fdclose
, fdread
, fdwrite
, fdioctl
,
264 nostop
, notty
, nopoll
, nommap
, nokqfilter
, D_DISK
267 struct dkdriver fddkdriver
= { fdstrategy
};
269 CFATTACH_DECL(fdc
, sizeof(struct device
),
270 fdcmatch
, fdcattach
, NULL
, NULL
);
273 * all hw access through macros, this helps to hide the active low
277 #define FDUNITMASK(unit) (1 << (3 + (unit)))
280 * select units using mask
282 #define FDSELECT(um) do { ciab.prb &= ~(um); } while (0)
285 * deselect units using mask
287 #define FDDESELECT(um) do { ciab.prb |= (um); delay(1); } while (0)
290 * test hw condition bits
292 #define FDTESTC(bit) ((ciaa.pra & (1 << (bit))) == 0)
295 * set motor for select units, true motor on else off
297 #define FDSETMOTOR(on) do { \
298 if (on) ciab.prb &= ~CIAB_PRB_MTR; else ciab.prb |= CIAB_PRB_MTR; \
302 * set head for select units
304 #define FDSETHEAD(head) do { \
305 if (head) ciab.prb &= ~CIAB_PRB_SIDE; else ciab.prb |= CIAB_PRB_SIDE; \
306 delay(1); } while (0)
309 * select direction, true towards spindle else outwards
311 #define FDSETDIR(in) do { \
312 if (in) ciab.prb &= ~CIAB_PRB_DIR; else ciab.prb |= CIAB_PRB_DIR; \
313 delay(1); } while (0)
316 * step the selected units
318 #define FDSTEP do { \
319 ciab.prb &= ~CIAB_PRB_STEP; ciab.prb |= CIAB_PRB_STEP; \
322 #define FDDMASTART(len, towrite) do { \
323 int dmasz = (len) | ((towrite) ? DISKLEN_WRITE : 0) | DISKLEN_DMAEN; \
324 custom.dsklen = dmasz; custom.dsklen = dmasz; } while (0)
326 #define FDDMASTOP do { custom.dsklen = 0; } while (0)
330 fdcmatch(struct device
*pdp
, struct cfdata
*cfp
, void *auxp
)
332 static int fdc_matched
= 0;
334 /* Allow only once instance. */
335 if (matchname("fdc", auxp
) == 0 || fdc_matched
)
337 if ((fdc_dmap
= alloc_chipmem(DMABUFSZ
)) == NULL
) {
338 printf("fdc: unable to allocate DMA buffer\n");
347 fdcattach(struct device
*pdp
, struct device
*dp
, void *auxp
)
351 printf(": dmabuf pa 0x%x", (unsigned)kvtop(fdc_dmap
));
352 printf(": dmabuf ka %p\n", fdc_dmap
);
354 args
.type
= fdcgetfdtype(args
.unit
);
357 config_found(dp
, &args
, fdcprint
);
358 for (args
.unit
++; args
.unit
< FDMAXUNITS
; args
.unit
++) {
359 if ((args
.type
= fdcgetfdtype(args
.unit
)) == NULL
)
361 config_found(dp
, &args
, fdcprint
);
366 fdcprint(void *auxp
, const char *pnp
)
372 aprint_normal("fd%d at %s unit %d:", fcp
->unit
, pnp
,
379 fdmatch(struct device
*pdp
, struct cfdata
*cfp
, void *auxp
)
381 struct fdcargs
*fdap
;
384 if (cfp
->cf_loc
[FDCCF_UNIT
] == fdap
->unit
||
385 cfp
->cf_loc
[FDCCF_UNIT
] == FDCCF_UNIT_DEFAULT
)
392 fdattach(struct device
*pdp
, struct device
*dp
, void *auxp
)
399 sc
= device_private(dp
);
401 bufq_alloc(&sc
->bufq
, "disksort", BUFQ_SORT_CYLINDER
);
402 callout_init(&sc
->calibrate_ch
, 0);
403 callout_init(&sc
->motor_ch
, 0);
405 sc
->curcyl
= sc
->cachetrk
= -1;
408 sc
->hwunit
= ap
->unit
;
409 sc
->unitmask
= 1 << (3 + ap
->unit
);
410 sc
->retries
= FDRETRIES
;
411 sc
->stepdelay
= FDSTEPDELAY
;
412 sc
->bytespersec
= 512;
413 printf(" unit %d: %s %d cyl, %d head, %d sec [%d sec], 512 bytes/sec\n",
414 sc
->hwunit
, sc
->type
->desc
, sc
->type
->ncylinders
, FDNHEADS
,
415 sc
->type
->amiga_nsectors
, sc
->type
->msdos_nsectors
);
418 * Initialize and attach the disk structure.
420 disk_init(&sc
->dkdev
, sc
->sc_dv
.dv_xname
, &fddkdriver
);
421 disk_attach(&sc
->dkdev
);
424 * calibrate the drive
427 fdsetpos(sc
, sc
->type
->ncylinders
, 0);
432 * precalc msdos MFM and CRC
434 for (i
= 0; i
< 128; i
++)
436 for (i
= 0; i
< 16; i
++)
437 msdecode
[msencode
[i
]] = i
;
438 for (i
= 0; i
< 256; i
++) {
439 mscrctab
[i
] = (0x1021 * (i
& 0xf0)) ^ (0x1021 * (i
& 0x0f)) ^
444 * enable disk related interrupts
446 custom
.dmacon
= DMAF_SETCLR
| DMAF_MASTER
| DMAF_DISK
;
447 custom
.intena
= INTF_SETCLR
| INTF_DSKBLK
;
448 ciab
.icr
= CIA_ICR_FLG
;
453 fdopen(dev_t dev
, int flags
, int devtype
, struct lwp
*l
)
456 int wasopen
, fwork
, error
, s
;
460 if (FDPART(dev
) >= FDMAXPARTS
)
463 if ((sc
= getsoftc(fd_cd
, FDUNIT(dev
))) == NULL
)
465 if (sc
->flags
& FDF_NOTRACK0
)
467 if (sc
->cachep
== NULL
)
468 sc
->cachep
= malloc(MAXTRKSZ
, M_DEVBUF
, M_WAITOK
);
472 * if we are sleeping in fdclose(); waiting for a chance to
473 * shut the motor off, do a sleep here also.
475 while (sc
->flags
& FDF_WMOTOROFF
)
476 tsleep(fdmotoroff
, PRIBIO
, "fdopen", 0);
480 * if not open let user open request type, otherwise
481 * ensure they are trying to open same type.
483 if (sc
->openpart
== FDPART(dev
))
485 else if (sc
->openpart
== -1) {
486 sc
->openpart
= FDPART(dev
);
495 * wait for current io to complete if any
500 tsleep(fdopen
, PRIBIO
, "fdopen", 0);
502 if ((error
= fdloaddisk(sc
)) != 0)
504 if ((error
= fdgetdisklabel(sc
, dev
)) != 0)
507 printf(" open successful\n");
511 * if we requested that fddone()->fdfindwork() wake us, allow it to
512 * complete its job now
515 fdfindwork(FDUNIT(dev
));
519 * if we were not open and we marked us so reverse that.
521 if (error
&& wasopen
== 0)
528 fdclose(dev_t dev
, int flags
, int devtype
, struct lwp
*l
)
534 printf("fdclose()\n");
536 sc
= getsoftc(fd_cd
, FDUNIT(dev
));
538 if (sc
->flags
& FDF_MOTORON
) {
539 sc
->flags
|= FDF_WMOTOROFF
;
540 tsleep(fdmotoroff
, PRIBIO
, "fdclose", 0);
541 sc
->flags
&= ~FDF_WMOTOROFF
;
550 fdioctl(dev_t dev
, u_long cmd
, void *addr
, int flag
, struct lwp
*l
)
555 sc
= getsoftc(fd_cd
, FDUNIT(dev
));
557 if ((sc
->flags
& FDF_HAVELABEL
) == 0)
564 if (*(int *)addr
< 0)
566 sc
->retries
= *(int *)addr
;
569 if (*(int *)addr
< FDSTEPDELAY
)
571 sc
->dkdev
.dk_label
->d_trkseek
= sc
->stepdelay
= *(int *)addr
;
574 *(struct disklabel
*)addr
= *(sc
->dkdev
.dk_label
);
577 ((struct partinfo
*)addr
)->disklab
= sc
->dkdev
.dk_label
;
578 ((struct partinfo
*)addr
)->part
=
579 &sc
->dkdev
.dk_label
->d_partitions
[FDPART(dev
)];
582 if ((flag
& FWRITE
) == 0)
584 return(fdsetdisklabel(sc
, (struct disklabel
*)addr
));
586 if ((flag
& FWRITE
) == 0)
588 if ((error
= fdsetdisklabel(sc
, (struct disklabel
*)addr
)) != 0)
592 error
= fdputdisklabel(sc
, dev
);
596 if ((flag
& FWRITE
) == 0)
598 sc
->wlabel
= *(int *)addr
;
601 fdgetdefaultlabel(sc
, (struct disklabel
*)addr
, FDPART(dev
));
609 fdread(dev_t dev
, struct uio
*uio
, int flags
)
611 return (physio(fdstrategy
, NULL
, dev
, B_READ
, fdminphys
, uio
));
615 fdwrite(dev_t dev
, struct uio
*uio
, int flags
)
617 return (physio(fdstrategy
, NULL
, dev
, B_WRITE
, fdminphys
, uio
));
628 fddmadone(fdc_indma
, 0);
635 if (fdc_indma
&& fdc_dmalen
) {
637 * turn off intr and start actual dma
639 ciab
.icr
= CIA_ICR_FLG
;
640 FDDMASTART(fdc_dmalen
, fdc_dmawrite
);
646 fdstrategy(struct buf
*bp
)
648 struct disklabel
*lp
;
652 unit
= FDUNIT(bp
->b_dev
);
653 part
= FDPART(bp
->b_dev
);
654 sc
= getsoftc(fd_cd
, unit
);
657 printf("fdstrategy: %p\n", bp
);
660 * check for valid partition and bounds
662 lp
= sc
->dkdev
.dk_label
;
663 if ((sc
->flags
& FDF_HAVELABEL
) == 0) {
667 if (bounds_check_with_label(&sc
->dkdev
, bp
, sc
->wlabel
) <= 0)
671 * trans count of zero or bounds check indicates io is done
674 if (bp
->b_bcount
== 0)
677 bp
->b_rawblkno
= bp
->b_blkno
;
680 * queue the buf and kick the low level code
683 bufq_put(sc
->bufq
, bp
);
688 bp
->b_resid
= bp
->b_bcount
;
693 * make sure disk is loaded and label is up-to-date.
696 fdloaddisk(struct fd_softc
*sc
)
699 * if diskchange is low step drive to 0 then up one then to zero.
701 fdselunit(sc
); /* make sure the unit is selected */
702 if (FDTESTC(FDB_CHANGED
)) {
704 sc
->cachetrk
= -1; /* invalidate the cache */
705 sc
->flags
&= ~FDF_HAVELABEL
;
706 fdsetpos(sc
, FDNHEADS
, 0);
708 if (FDTESTC(FDB_CHANGED
)) {
710 FDDESELECT(sc
->unitmask
);
714 FDDESELECT(sc
->unitmask
);
716 sc
->type
= fdcgetfdtype(sc
->hwunit
);
717 if (sc
->type
== NULL
)
719 if (sc
->openpart
== FDMSDOSPART
)
720 sc
->nsectors
= sc
->type
->msdos_nsectors
;
722 sc
->nsectors
= sc
->type
->amiga_nsectors
;
727 fdgetdefaultlabel(struct fd_softc
*sc
, struct disklabel
*lp
, int part
)
728 /* (variable part) XXX ick */
731 memset(lp
, 0, sizeof(struct disklabel
));
732 lp
->d_secsize
= FDSECSIZE
;
733 lp
->d_ntracks
= FDNHEADS
;
734 lp
->d_ncylinders
= sc
->type
->ncylinders
;
735 lp
->d_nsectors
= sc
->nsectors
;
736 lp
->d_secpercyl
= lp
->d_ntracks
* lp
->d_nsectors
;
737 lp
->d_type
= DTYPE_FLOPPY
;
738 lp
->d_secperunit
= lp
->d_secpercyl
* lp
->d_ncylinders
;
739 lp
->d_rpm
= 300; /* good guess I suppose. */
740 lp
->d_interleave
= 1; /* should change when adding msdos */
741 sc
->stepdelay
= lp
->d_trkseek
= FDSTEPDELAY
;
744 lp
->d_partitions
[part
].p_size
= lp
->d_secperunit
;
745 lp
->d_partitions
[part
].p_fstype
= FS_UNUSED
;
746 lp
->d_partitions
[part
].p_fsize
= 1024;
747 lp
->d_partitions
[part
].p_frag
= 8;
748 lp
->d_partitions
[part
].p_cpg
= 2; /* adosfs: reserved blocks */
749 lp
->d_npartitions
= part
+ 1;
750 lp
->d_magic
= lp
->d_magic2
= DISKMAGIC
;
751 lp
->d_checksum
= dkcksum(lp
);
755 * read disk label, if present otherwise create one
756 * return a new label if raw part and none found, otherwise err.
759 fdgetdisklabel(struct fd_softc
*sc
, dev_t dev
)
761 struct disklabel
*lp
, *dlp
;
762 struct cpu_disklabel
*clp
;
766 if (sc
->flags
& FDF_HAVELABEL
&&
767 sc
->dkdev
.dk_label
->d_npartitions
== (FDPART(dev
) + 1))
770 printf("fdgetdisklabel()\n");
773 lp
= sc
->dkdev
.dk_label
;
774 clp
= sc
->dkdev
.dk_cpulabel
;
775 memset(lp
, 0, sizeof(struct disklabel
));
776 memset(clp
, 0, sizeof(struct cpu_disklabel
));
778 lp
->d_secsize
= FDSECSIZE
;
779 lp
->d_ntracks
= FDNHEADS
;
780 lp
->d_ncylinders
= sc
->type
->ncylinders
;
781 lp
->d_nsectors
= sc
->nsectors
;
782 lp
->d_secpercyl
= lp
->d_ntracks
* lp
->d_nsectors
;
783 lp
->d_secperunit
= lp
->d_secpercyl
* lp
->d_ncylinders
;
784 lp
->d_npartitions
= part
+ 1;
785 lp
->d_partitions
[part
].p_size
= lp
->d_secperunit
;
786 lp
->d_partitions
[part
].p_fstype
= FS_UNUSED
;
787 lp
->d_partitions
[part
].p_fsize
= 1024;
788 lp
->d_partitions
[part
].p_frag
= 8;
789 lp
->d_partitions
[part
].p_cpg
= 2; /* for adosfs: reserved blks */
791 sc
->flags
|= FDF_HAVELABEL
;
793 bp
= (void *)geteblk((int)lp
->d_secsize
);
797 bp
->b_bcount
= FDSECSIZE
;
798 bp
->b_flags
|= B_READ
;
800 if ((error
= biowait(bp
)) != 0)
802 dlp
= (struct disklabel
*)((char*)bp
->b_data
+ LABELOFFSET
);
803 if (dlp
->d_magic
!= DISKMAGIC
|| dlp
->d_magic2
!= DISKMAGIC
||
808 memcpy(lp
, dlp
, sizeof(struct disklabel
));
809 if (lp
->d_trkseek
> FDSTEPDELAY
)
810 sc
->stepdelay
= lp
->d_trkseek
;
814 fdgetdefaultlabel(sc
, lp
, part
);
820 * set the incore copy of this units disklabel
823 fdsetdisklabel(struct fd_softc
*sc
, struct disklabel
*lp
)
825 struct disklabel
*clp
;
826 struct partition
*pp
;
829 * must have at least opened raw unit to fetch the
832 if ((sc
->flags
& FDF_HAVELABEL
) == 0)
834 clp
= sc
->dkdev
.dk_label
;
836 * make sure things check out and we only have one valid
840 printf("fdsetdisklabel\n");
842 if (lp
->d_secsize
!= FDSECSIZE
||
843 lp
->d_nsectors
!= clp
->d_nsectors
||
844 lp
->d_ntracks
!= FDNHEADS
||
845 lp
->d_ncylinders
!= clp
->d_ncylinders
||
846 lp
->d_secpercyl
!= clp
->d_secpercyl
||
847 lp
->d_secperunit
!= clp
->d_secperunit
||
848 lp
->d_magic
!= DISKMAGIC
||
849 lp
->d_magic2
!= DISKMAGIC
||
850 lp
->d_npartitions
== 0 ||
851 lp
->d_npartitions
> FDMAXPARTS
||
852 (lp
->d_partitions
[0].p_offset
&& lp
->d_partitions
[1].p_offset
) ||
856 * if any partitions are present make sure they
857 * represent the currently open type
859 if ((pp
= &lp
->d_partitions
[0])->p_size
) {
860 if ((pp
= &lp
->d_partitions
[1])->p_size
== 0)
862 else if (sc
->openpart
!= 1)
864 } else if (sc
->openpart
!= 0)
867 * make sure selected partition is within bounds
868 * XXX on the second check, its to handle a bug in
869 * XXX the cluster routines as they require mutliples
870 * XXX of PAGE_SIZE currently
872 if ((pp
->p_offset
+ pp
->p_size
>= lp
->d_secperunit
) ||
873 (pp
->p_frag
* pp
->p_fsize
% PAGE_SIZE
))
876 memcpy(clp
, lp
, sizeof(struct disklabel
));
881 * write out the incore copy of this units disklabel
884 fdputdisklabel(struct fd_softc
*sc
, dev_t dev
)
886 struct disklabel
*lp
, *dlp
;
890 if ((sc
->flags
& FDF_HAVELABEL
) == 0)
893 printf("fdputdisklabel\n");
896 * get buf and read in sector 0
898 lp
= sc
->dkdev
.dk_label
;
899 bp
= geteblk((int)lp
->d_secsize
);
900 bp
->b_dev
= FDMAKEDEV(major(dev
), FDUNIT(dev
), RAW_PART
);
903 bp
->b_bcount
= FDSECSIZE
;
904 bp
->b_flags
|= B_READ
;
906 if ((error
= biowait(bp
)) != 0)
909 * copy disklabel to buf and write it out synchronous
911 dlp
= (struct disklabel
*)((char*)bp
->b_data
+ LABELOFFSET
);
912 memcpy(dlp
, lp
, sizeof(struct disklabel
));
915 bp
->b_flags
&= ~(B_READ
);
916 bp
->b_oflags
&= ~(BO_DONE
);
917 bp
->b_flags
|= B_WRITE
;
926 * figure out drive type or NULL if none.
929 fdcgetfdtype(int unit
)
936 umask
= 1 << (3 + unit
);
938 FDDESELECT(FDCUNITMASK
);
952 for (idb
= 0x80000000; idb
; idb
>>= 1) {
955 if (FDTESTC(FDB_READY
) == 0)
961 printf("fdcgettype unit %d id 0x%lx\n", unit
, id
);
964 for (cnt
= 0, ftp
= fdtype
; cnt
< nfdtype
; ftp
++, cnt
++)
965 if (ftp
->driveid
== id
)
968 * 3.5dd's at unit 0 do not always return id.
976 * turn motor off if possible otherwise mark as needed and will be done
980 fdmotoroff(void *arg
)
989 printf("fdmotoroff: unit %d\n", sc
->hwunit
);
991 if ((sc
->flags
& FDF_MOTORON
) == 0)
994 * if we have a timeout on a DMA operation let fddmadone()
997 if (fdc_indma
== sc
) {
1002 printf(" motor was on, turning off\n");
1006 * flush cache if needed
1008 if (sc
->flags
& FDF_DIRTY
) {
1009 sc
->flags
|= FDF_JUSTFLUSH
| FDF_MOTOROFF
;
1011 printf(" flushing dirty buffer first\n");
1014 * if DMA'ing done for now, fddone() will call us again
1018 fddmastart(sc
, sc
->cachetrk
);
1023 * if controller is busy just schedule us to be called back
1027 * someone else has the controller now
1028 * just set flag and let fddone() call us again.
1030 sc
->flags
|= FDF_MOTOROFF
;
1035 printf(" hw turning unit off\n");
1038 sc
->flags
&= ~(FDF_MOTORON
| FDF_MOTOROFF
);
1039 FDDESELECT(FDCUNITMASK
);
1042 FDSELECT(sc
->unitmask
);
1044 FDDESELECT(sc
->unitmask
);
1046 if (sc
->flags
& FDF_WMOTOROFF
)
1053 * select drive seek to track exit with motor on.
1054 * fdsetpos(x, 0, 0) does calibrates the drive.
1057 fdsetpos(struct fd_softc
*sc
, int trk
, int towrite
)
1059 int nstep
, sdir
, ondly
, ncyl
, nside
;
1061 FDDESELECT(FDCUNITMASK
);
1064 FDSELECT(sc
->unitmask
);
1066 if ((sc
->flags
& FDF_MOTORON
) == 0) {
1068 while (FDTESTC(FDB_READY
) == 0) {
1070 if (++ondly
>= 1000)
1074 sc
->flags
|= FDF_MOTORON
;
1076 ncyl
= trk
/ FDNHEADS
;
1077 nside
= trk
% FDNHEADS
;
1079 if (sc
->curcyl
== ncyl
&& fdc_side
== nside
)
1083 sc
->flags
|= FDF_WRITEWAIT
;
1086 printf("fdsetpos: cyl %d head %d towrite %d\n", trk
/ FDNHEADS
,
1087 trk
% FDNHEADS
, towrite
);
1089 nstep
= ncyl
- sc
->curcyl
;
1094 if (nstep
> 0 && ncyl
!= 0) {
1104 * either just want cylinder 0 or doing
1108 while (FDTESTC(FDB_CYLZERO
) == 0 && nstep
--) {
1110 delay(sc
->stepdelay
);
1113 sc
->flags
|= FDF_NOTRACK0
;
1116 * step the needed amount amount.
1120 delay(sc
->stepdelay
);
1124 * if switched directions
1125 * allow drive to settle.
1127 if (sc
->pstepdir
!= sdir
)
1128 delay(FDSETTLEDELAY
);
1129 sc
->pstepdir
= sdir
;
1132 if (nside
== fdc_side
)
1139 delay(FDPRESIDEDELAY
);
1143 fdselunit(struct fd_softc
*sc
)
1145 FDDESELECT(FDCUNITMASK
); /* deselect all */
1146 FDSETMOTOR(sc
->flags
& FDF_MOTORON
); /* set motor to unit's state */
1148 FDSELECT(sc
->unitmask
); /* select unit */
1153 * process next buf on device queue.
1154 * normall sequence of events:
1155 * fdstart() -> fddmastart();
1157 * fdintr() -> fddmadone() -> fddone();
1158 * if the track is in the cache then fdstart() will short-circuit
1159 * to fddone() else if the track cache is dirty it will flush. If
1160 * the buf is not an entire track it will cache the requested track.
1163 fdstart(struct fd_softc
*sc
)
1165 int trk
, error
, write
;
1166 struct buf
*bp
, *dp
;
1170 printf("fdstart: unit %d\n", sc
->hwunit
);
1174 * if DMA'ing just return. we must have been called from fdstartegy.
1180 * get next buf if there.
1183 if ((bp
= bufq_peek(sc
->bufq
)) == NULL
) {
1185 printf(" nothing to do\n");
1191 * Mark us as busy now, in case fddone() gets called in one
1192 * of the cases below.
1194 disk_busy(&sc
->dkdev
);
1197 * make sure same disk is loaded
1200 changed
= FDTESTC(FDB_CHANGED
);
1201 FDDESELECT(sc
->unitmask
);
1204 * disk missing, invalidate all future io on
1205 * this unit until re-open()'ed also invalidate
1208 printf("fdstart: disk changed\n");
1210 printf(" disk was removed invalidating all io\n");
1212 sc
->flags
&= ~FDF_HAVELABEL
;
1214 bp
= bufq_get(sc
->bufq
);
1216 if (bufq_peek(sc
->bufq
) == NULL
)
1221 * do fddone() on last buf to allow other units to start.
1223 bufq_put(sc
->bufq
, bp
);
1229 * we have a valid buf, setup our local version
1230 * we use this count to allow reading over multiple tracks.
1231 * into a single buffer
1233 dp
->b_bcount
= bp
->b_bcount
;
1234 dp
->b_blkno
= bp
->b_blkno
;
1235 dp
->b_data
= bp
->b_data
;
1236 dp
->b_flags
= bp
->b_flags
;
1239 if (bp
->b_flags
& B_READ
)
1241 else if (FDTESTC(FDB_PROTECT
) == 0)
1249 * figure trk given blkno
1251 trk
= bp
->b_blkno
/ sc
->nsectors
;
1254 * check to see if same as currently cached track
1255 * if so we need to do no DMA read.
1257 if (trk
== sc
->cachetrk
) {
1263 * if we will be overwriting the entire cache, don't bother to
1266 if (bp
->b_bcount
== (sc
->nsectors
* FDSECSIZE
) && write
&&
1267 bp
->b_blkno
% sc
->nsectors
== 0) {
1268 if (sc
->flags
& FDF_DIRTY
)
1269 sc
->flags
|= FDF_JUSTFLUSH
;
1278 * start DMA read of `trk'
1280 fddmastart(sc
, trk
);
1283 bp
->b_error
= error
;
1288 * continue a started operation on next track. always begin at
1289 * sector 0 on the next track.
1292 fdcont(struct fd_softc
*sc
)
1294 struct buf
*dp
, *bp
;
1298 bp
= bufq_peek(sc
->bufq
);
1299 dp
->b_data
= (char*)dp
->b_data
+ (dp
->b_bcount
- bp
->b_resid
);
1300 dp
->b_blkno
+= (dp
->b_bcount
- bp
->b_resid
) / FDSECSIZE
;
1301 dp
->b_bcount
= bp
->b_resid
;
1304 * figure trk given blkno
1306 trk
= dp
->b_blkno
/ sc
->nsectors
;
1308 if (trk
!= sc
->cachetrk
+ 1 || dp
->b_blkno
% sc
->nsectors
!= 0)
1309 panic("fdcont: confused");
1311 if (dp
->b_flags
& B_READ
)
1316 * if we will be overwriting the entire cache, don't bother to
1319 if (dp
->b_bcount
== (sc
->nsectors
* FDSECSIZE
) && write
) {
1320 if (sc
->flags
& FDF_DIRTY
)
1321 sc
->flags
|= FDF_JUSTFLUSH
;
1329 * start DMA read of `trk'
1331 fddmastart(sc
, trk
);
1336 fddmastart(struct fd_softc
*sc
, int trk
)
1338 int adkmask
, ndmaw
, write
, dmatrk
;
1341 printf("fddmastart: unit %d cyl %d head %d", sc
->hwunit
,
1342 trk
/ FDNHEADS
, trk
% FDNHEADS
);
1345 * flush the cached track if dirty else read requested track.
1347 if (sc
->flags
& FDF_DIRTY
) {
1349 ndmaw
= sc
->type
->nwritew
;
1350 dmatrk
= sc
->cachetrk
;
1353 ndmaw
= sc
->type
->nreadw
;
1359 printf(" %s", write
? " flushing cache\n" : " loading cache\n");
1363 fdsetpos(sc
, dmatrk
, write
);
1369 custom
.adkcon
= ADKF_MSBSYNC
;
1370 custom
.adkcon
= ADKF_SETCLR
| ADKF_WORDSYNC
| ADKF_FAST
;
1371 custom
.dsksync
= FDMFMSYNC
;
1373 custom
.adkcon
= ADKF_PRECOMP1
| ADKF_PRECOMP0
| ADKF_WORDSYNC
|
1375 adkmask
= ADKF_SETCLR
| ADKF_FAST
| ADKF_MFMPREC
;
1376 if (dmatrk
>= sc
->type
->precomp
[0])
1377 adkmask
|= ADKF_PRECOMP0
;
1378 if (dmatrk
>= sc
->type
->precomp
[1])
1379 adkmask
|= ADKF_PRECOMP1
;
1380 custom
.adkcon
= adkmask
;
1382 custom
.dskpt
= (u_char
*)kvtop(fdc_dmap
);
1385 * If writing an MSDOS track, activate disk index pulse
1386 * interrupt, DMA will be started in the intr routine fdidxintr()
1387 * Otherwise, start the DMA here.
1389 if (write
&& sc
->openpart
== FDMSDOSPART
) {
1391 fdc_dmawrite
= write
;
1392 ciab
.icr
= CIA_ICR_IR_SC
| CIA_ICR_FLG
;
1394 FDDMASTART(ndmaw
, write
);
1399 printf(" DMA started\n");
1404 * recalibrate the drive
1407 fdcalibrate(void *arg
)
1409 struct fd_softc
*sc
;
1419 sc
->stepdelay
+= 900;
1420 if (sc
->cachetrk
> 1)
1421 fdsetpos(sc
, sc
->cachetrk
% FDNHEADS
, 0);
1422 sc
->stepdelay
-= 900;
1425 fdsetpos(sc
, sc
->cachetrk
, 0);
1427 fdsetpos(sc
, sc
->cachetrk
+ FDNHEADS
, 0);
1429 * trk++, trk, trk++, trk, trk++, trk, trk++, trk and DMA
1432 callout_reset(&sc
->calibrate_ch
, hz
/ 8, fdcalibrate
, sc
);
1436 callout_reset(&sc
->motor_ch
, 3 * hz
/ 2, fdmotoroff
, sc
);
1437 fddmastart(sc
, sc
->cachetrk
);
1442 fddmadone(struct fd_softc
*sc
, int timeo
)
1445 printf("fddmadone: unit %d, timeo %d\n", sc
->hwunit
, timeo
);
1448 callout_stop(&sc
->motor_ch
);
1452 * guarantee the drive has been at current head and cyl
1453 * for at least FDWRITEDELAY after a write.
1455 if (sc
->flags
& FDF_WRITEWAIT
) {
1456 delay(FDWRITEDELAY
);
1457 sc
->flags
&= ~FDF_WRITEWAIT
;
1460 if ((sc
->flags
& FDF_MOTOROFF
) == 0) {
1462 * motor runs for 1.5 seconds after last DMA
1464 callout_reset(&sc
->motor_ch
, 3 * hz
/ 2, fdmotoroff
, sc
);
1466 if (sc
->flags
& FDF_DIRTY
) {
1468 * if buffer dirty, the last DMA cleaned it
1470 sc
->flags
&= ~FDF_DIRTY
;
1472 printf("%s: write of track cache timed out.\n",
1473 sc
->sc_dv
.dv_xname
);
1474 if (sc
->flags
& FDF_JUSTFLUSH
) {
1475 sc
->flags
&= ~FDF_JUSTFLUSH
;
1477 * we are done DMA'ing
1485 fddmastart(sc
, sc
->cachetrk
);
1489 else if (sc
->flags
& FDF_MOTOROFF
)
1490 panic("fddmadone: FDF_MOTOROFF with no FDF_DIRTY");
1494 * cache loaded decode it into cache buffer
1496 if (timeo
== 0 && fdrawtocache(sc
) == 0)
1501 printf("%s: fddmadone: cache load timed out.\n",
1502 sc
->sc_dv
.dv_xname
);
1504 if (sc
->retried
>= sc
->retries
) {
1510 * this will be restarted at end of calibrate loop.
1512 callout_stop(&sc
->motor_ch
);
1521 fddone(struct fd_softc
*sc
)
1523 struct buf
*dp
, *bp
;
1528 printf("fddone: unit %d\n", sc
->hwunit
);
1531 * check to see if unit is just flushing the cache,
1532 * that is we have no io queued.
1534 if (sc
->flags
& FDF_MOTOROFF
)
1538 if ((bp
= bufq_peek(sc
->bufq
)) == NULL
)
1541 * check for an error that may have occurred
1542 * while getting the track.
1544 if (sc
->cachetrk
== -1) {
1547 } else if (bp
->b_error
== 0) {
1550 * get offset of data in track cache and limit
1551 * the copy size to not exceed the cache's end.
1553 data
+= (dp
->b_blkno
% sc
->nsectors
) * FDSECSIZE
;
1554 sz
= sc
->nsectors
- dp
->b_blkno
% sc
->nsectors
;
1556 sz
= min(dp
->b_bcount
, sz
);
1557 if (bp
->b_flags
& B_READ
)
1558 memcpy(dp
->b_data
, data
, sz
);
1560 memcpy(data
, dp
->b_data
, sz
);
1561 sc
->flags
|= FDF_DIRTY
;
1563 bp
->b_resid
= dp
->b_bcount
- sz
;
1564 if (bp
->b_resid
== 0) {
1568 * not done yet need to read next track
1575 * remove from queue.
1577 (void)bufq_get(sc
->bufq
);
1579 disk_unbusy(&sc
->dkdev
, (bp
->b_bcount
- bp
->b_resid
),
1580 (bp
->b_flags
& B_READ
));
1584 fdfindwork(device_unit(&sc
->sc_dv
));
1588 fdfindwork(int unit
)
1590 struct fd_softc
*ssc
, *sc
;
1594 * first see if we have any fdopen()'s waiting
1596 if (fdc_wantwakeup
) {
1603 * start next available unit, linear search from the next unit
1604 * wrapping and finally this unit.
1608 for (i
= unit
+ 1; last
== 0; i
++) {
1611 if (i
>= fd_cd
.cd_ndevs
) {
1615 if ((sc
= device_lookup_private(&fd_cd
, i
)) == NULL
)
1619 * if unit has requested to be turned off
1620 * and it has no buf's queued do it now
1622 if (sc
->flags
& FDF_MOTOROFF
) {
1623 if (bufq_peek(sc
->bufq
) == NULL
)
1627 * we gained a buf request while
1628 * we waited, forget the motoroff
1630 sc
->flags
&= ~FDF_MOTOROFF
;
1633 * if we now have DMA unit must have needed
1640 * if we have no start unit and the current unit has
1641 * io waiting choose this unit to start.
1643 if (ssc
== NULL
&& bufq_peek(sc
->bufq
) != NULL
)
1651 * min byte count to whats left of the track in question
1654 fdminphys(struct buf
*bp
)
1656 struct fd_softc
*sc
;
1657 int trk
, sec
, toff
, tsz
;
1659 if ((sc
= getsoftc(fd_cd
, FDUNIT(bp
->b_dev
))) == NULL
)
1660 panic("fdminphys: couldn't get softc");
1662 trk
= bp
->b_blkno
/ sc
->nsectors
;
1663 sec
= bp
->b_blkno
% sc
->nsectors
;
1665 toff
= sec
* FDSECSIZE
;
1666 tsz
= sc
->nsectors
* FDSECSIZE
;
1668 printf("fdminphys: before %ld", bp
->b_bcount
);
1670 bp
->b_bcount
= min(bp
->b_bcount
, tsz
- toff
);
1672 printf(" after %ld\n", bp
->b_bcount
);
1678 * encode the track cache into raw MFM ready for DMA
1679 * when we go to multiple disk formats, this will call type dependent
1682 void fdcachetoraw(struct fd_softc
*sc
)
1684 if (sc
->openpart
== FDMSDOSPART
)
1691 * decode raw MFM from DMA into units track cache.
1692 * when we go to multiple disk formats, this will call type dependent
1696 fdrawtocache(struct fd_softc
*sc
)
1699 if (sc
->openpart
== FDMSDOSPART
)
1700 return(msrawtocache(sc
));
1702 return(amrawtocache(sc
));
1706 amcachetoraw(struct fd_softc
*sc
)
1708 static u_long mfmnull
[4];
1709 u_long
*rp
, *crp
, *dp
, hcksum
, dcksum
, info
, zero
;
1715 * not yet one sector (- 1 long) gap.
1716 * for now use previous drivers values
1718 for (i
= 0; i
< sc
->type
->gap
; i
++)
1725 info
= 0xff000000 | (sc
->cachetrk
<< 16) | sc
->nsectors
;
1726 for (sec
= 0; sec
< sc
->nsectors
; sec
++, info
+= (1 << 8) - 1) {
1727 hcksum
= dcksum
= 0;
1730 * offset description
1731 *-----------------------------------
1735 *----------------------
1736 * 2 3 [0xff]b [trk]b [sec]b [togap]b
1738 * 12 13 header cksum [2-11]
1739 * 14 15 data cksum [16-271]
1740 * 16-143 144-271 data
1743 if (*(rp
- 1) & 0x1)
1744 *rp
&= 0x7fffffff; /* clock bit correction */
1746 *rp
++ = (FDMFMSYNC
<< 16) | FDMFMSYNC
;
1747 rp
= mfmblkencode(&info
, rp
, &hcksum
, 1);
1748 rp
= mfmblkencode(mfmnull
, rp
, &hcksum
, 4);
1749 rp
= mfmblkencode(&hcksum
, rp
, NULL
, 1);
1752 rp
= mfmblkencode(dp
, rp
+ 2, &dcksum
, FDSECLWORDS
);
1754 crp
= mfmblkencode(&dcksum
, crp
, NULL
, 1);
1755 if (*(crp
- 1) & 0x1)
1756 *crp
&= 0x7fffffff; /* clock bit correction */
1757 else if ((*crp
& 0x40000000) == 0)
1761 if (*(rp
- 1) & 0x1)
1766 fdfindsync(u_long
*rp
, u_long
*ep
)
1771 while ((u_long
*)sp
< ep
&& *sp
!= FDMFMSYNC
)
1773 while ((u_long
*)sp
< ep
&& *sp
== FDMFMSYNC
)
1775 if ((u_long
*)sp
< ep
)
1776 return((u_long
*)sp
);
1781 amrawtocache(struct fd_softc
*sc
)
1784 u_long
*dp
, *rp
, *erp
, *crp
, *srp
, hcksum
, dcksum
, info
, cktmp
;
1788 srp
= rp
= fdc_dmap
;
1789 erp
= (u_long
*)((u_short
*)rp
+ sc
->type
->nreadw
);
1792 if (doagain
== 0 || (rp
= srp
= fdfindsync(srp
, erp
)) == NULL
) {
1794 printf("%s: corrupted track (%d) data.\n",
1795 sc
->sc_dv
.dv_xname
, sc
->cachetrk
);
1803 for (; cnt
< sc
->nsectors
; cnt
++) {
1804 hcksum
= dcksum
= 0;
1805 rp
= mfmblkdecode(rp
, &info
, &hcksum
, 1);
1806 rp
= mfmblkdecode(rp
, mfmnull
, &hcksum
, 4);
1807 rp
= mfmblkdecode(rp
, &cktmp
, NULL
, 1);
1808 if (cktmp
!= hcksum
) {
1810 printf(" info 0x%lx hchksum 0x%lx trkhcksum 0x%lx\n",
1811 info
, hcksum
, cktmp
);
1815 if (((info
>> 16) & 0xff) != sc
->cachetrk
) {
1817 printf("%s: incorrect track found: 0x%lx %d\n",
1818 sc
->sc_dv
.dv_xname
, info
, sc
->cachetrk
);
1823 printf(" info 0x%lx\n", info
);
1826 rp
= mfmblkdecode(rp
, &cktmp
, NULL
, 1);
1828 dp
+= FDSECLWORDS
* ((info
>> 8) & 0xff);
1829 crp
= mfmblkdecode(rp
, dp
, &dcksum
, FDSECLWORDS
);
1830 if (cktmp
!= dcksum
) {
1832 printf(" info 0x%lx dchksum 0x%lx trkdcksum 0x%lx\n",
1833 info
, dcksum
, cktmp
);
1839 * if we are at gap then we can no longer be sure
1840 * of correct sync marks
1842 if ((info
&& 0xff) == 1)
1846 srp
= rp
= fdfindsync(crp
, erp
);
1852 mscachetoraw(struct fd_softc
*sc
)
1854 u_short
*rp
, *erp
, crc
;
1858 rp
= (u_short
*)fdc_dmap
;
1859 erp
= rp
+ sc
->type
->nwritew
;
1863 * initial track filler (828 * GAP1)
1865 for (i
= 0; i
< sc
->type
->gap
; i
++) {
1870 for (sec
= 0; sec
< sc
->nsectors
; sec
++) {
1873 * leading sector gap
1874 * (12 * GAP2) + (3 * SYNC)
1876 for (i
= 0; i
< 12; i
++)
1883 * sector information
1884 * (ID) + track + side + sector + sector size + CRC16
1887 tb
[0] = sc
->cachetrk
/ FDNHEADS
;
1888 tb
[1] = sc
->cachetrk
% FDNHEADS
;
1890 i
= sc
->bytespersec
;
1891 tb
[3] = i
< 256 ? 0 : (i
< 512 ? 1 : (i
< 1024 ? 2 : 3));
1892 rp
= msblkencode(rp
, tb
, 4, &crc
);
1895 tb
[2] = 0x4e; /* GAP1 decoded */
1896 rp
= msblkencode(rp
, tb
, 3, 0);
1899 * sector info/data gap
1900 * (22 * GAP1) + (12 * GAP2) + (3 * SYNC)
1902 for (i
= 0; i
< 21; i
++)
1904 for (i
= 0; i
< 12; i
++)
1912 * (DATA) + ...data... + CRC16
1915 rp
= msblkencode(rp
, cp
, sc
->bytespersec
, &crc
);
1916 cp
+= sc
->bytespersec
;
1919 tb
[2] = 0x4e; /* GAP3 decoded */
1920 rp
= msblkencode(rp
, tb
, 3, 0);
1923 * trailing sector gap
1926 for (i
= 0; i
< 79; i
++)
1931 * fill rest of track with GAP3
1939 msrawtocache(struct fd_softc
*sc
)
1941 u_short
*rp
, *srp
, *erp
;
1945 srp
= rp
= (u_short
*)fdc_dmap
;
1946 erp
= rp
+ sc
->type
->nreadw
;
1949 for (ct
= 0; ct
< sc
->nsectors
; ct
++) {
1953 * skip leading gap to sync
1955 if ((rp
= (u_short
*)fdfindsync((u_long
*)rp
, (u_long
*)erp
)) == NULL
) {
1957 printf("%s: corrupted track (%d) data.\n",
1958 sc
->sc_dv
.dv_xname
, sc
->cachetrk
);
1966 if (*rp
++ != FDMFMID
)
1968 rp
= msblkdecode(rp
, tb
, 4);
1970 printf("sector id: sector %d, track %d, side %d,"
1971 "bps %d\n", tb
[2], tb
[0], tb
[1], 128 << tb
[3]);
1973 if ((tb
[0] * FDNHEADS
+ tb
[1]) != sc
->cachetrk
||
1974 tb
[2] > sc
->nsectors
)
1978 sc
->bytespersec
= 128 << tb
[3];
1979 rp
+= 2; /* skip CRC-16 */
1982 * skip gap and read in data
1984 if ((rp
= (u_short
*)fdfindsync((u_long
*)rp
, (u_long
*)erp
)) == NULL
)
1986 if (*rp
++ != FDMFMDATA
)
1988 rp
= msblkdecode(rp
, cp
+ ((sec
-1) * sc
->bytespersec
),
1990 rp
+= 2; /* skip CRC-16 */
1999 * encode len longwords of `dp' data in amiga mfm block format (`rp')
2000 * this format specified that the odd bits are at current pos and even
2001 * bits at len + current pos
2004 mfmblkencode(u_long
*dp
, u_long
*rp
, u_long
*cp
, int len
)
2006 u_long
*sdp
, *edp
, d
, dtmp
, correct
;
2011 if (*(rp
- 1) & 0x1)
2019 d
= (*dp
>> 1) & 0x55555555; /* remove clock bits */
2020 dtmp
= d
^ 0x55555555;
2021 d
|= ((dtmp
>> 1) | 0x80000000) & (dtmp
<< 1);
2023 * correct upper clock bit if needed
2032 * do checksums and store in raw buffer
2044 d
= *dp
& 0x55555555; /* remove clock bits */
2045 dtmp
= d
^ 0x55555555;
2046 d
|= ((dtmp
>> 1) | 0x80000000) & (dtmp
<< 1);
2048 * correct upper clock bit if needed
2057 * do checksums and store in raw buffer
2070 * decode len longwords of `dp' data in amiga mfm block format (`rp')
2071 * this format specified that the odd bits are at current pos and even
2072 * bits at len + current pos
2075 mfmblkdecode(u_long
*rp
, u_long
*dp
, u_long
*cp
, int len
)
2090 *dp
++ = (o
<< 1) | e
;
2099 * decode len words in standard MFM format to len bytes
2103 msblkdecode(u_short
*rp
, u_char
*cp
, int len
)
2106 *cp
++ = msdecode
[*rp
& 0x7f] |
2107 (msdecode
[(*rp
>> 8) & 0x7f] << 4);
2115 * encode len bytes of data into len words in standard MFM format.
2116 * If a pointer is supplied for crc, calculate the CRC-16 of the data
2120 msblkencode(u_short
*rp
, u_char
*cp
, int len
, u_short
*crc
)
2125 /* preload crc for header (4 bytes)
2126 * or data (anything else)
2128 mycrc
= (len
== 4) ? 0xb230 : 0xe295;
2131 td
= (msencode
[*cp
>> 4] << 8) | msencode
[*cp
& 0x0f];
2133 /* Check for zeros in top bit of encode and bottom
2134 * bit of previous encode. if so, slap a one in betweem
2137 if ((td
& 0x140) == 0)
2139 if ((td
& 0x4000) == 0 && (rp
[-1] & 1) == 0)
2145 * calc crc if requested
2148 mycrc
= (mycrc
<< 8) ^ mscrctab
[*cp
^ (mycrc
>> 8)];