-/* $OpenBSD: fd.c,v 1.8 1996/05/04 13:31:20 niklas Exp $ */
-/* $NetBSD: fd.c,v 1.31 1996/04/30 06:09:51 mhitch Exp $ */
+/* $OpenBSD: fd.c,v 1.9 1996/05/07 10:08:23 niklas Exp $ */
+/* $NetBSD: fd.c,v 1.32 1996/05/04 04:54:00 mhitch Exp $ */
/*
* Copyright (c) 1994 Christian E. Hopps
+ * Copyright (c) 1996 Ezra Story
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Christian E. Hopps.
+ * This product includes software developed by Ezra Story.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
#include <sys/dkbad.h>
#include <sys/proc.h>
#include <machine/cpu.h>
+#include <machine/intr.h>
#include <amiga/amiga/device.h>
#include <amiga/amiga/custom.h>
#include <amiga/amiga/cia.h>
#include <amiga/amiga/cc.h>
+#include <amiga/amiga/isr.h>
#include <sys/conf.h>
#include <machine/conf.h>
*/
enum fd_parttypes {
FDAMIGAPART = 0,
-#ifdef not_yet
FDMSDOSPART,
-#endif
FDMAXPARTS
};
#define FDPART(dev) DISKPART(dev)
#define FDMAKEDEV(m, u, p) MAKEDISKDEV((m), (u), (p))
+/* that's nice, but we don't want to always use this as an amiga drive
+bunghole :-) */
#define FDNHEADS (2) /* amiga drives always have 2 heads */
#define FDSECSIZE (512) /* amiga drives always have 512 byte sectors */
#define FDSECLWORDS (128)
#define DMABUFSZ ((DISKLEN_WRITE - 1) * 2) /* largest dma possible */
#define FDMFMSYNC (0x4489)
+#define FDMFMID (0x5554)
+#define FDMFMDATA (0x5545)
+#define FDMFMGAP1 (0x9254)
+#define FDMFMGAP2 (0xAAAA)
+#define FDMFMGAP3 (0x9254)
+#define CRC16POLY (0x1021) /* (x^16) + x^12 + x^5 + x^0 */
+
+/*
+ * Msdos-type MFM encode/decode
+ */
+static u_char msdecode[128];
+static u_char msencode[16] =
+{
+ 0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15,
+ 0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55
+};
+static u_short mscrctab[256];
+
+/*
+ 5554 aaaa aaaa aaa5 2aa4 4452 aa51
+ 00 00 03 02 ac 0d
+*/
/*
* floppy device type
int openpart; /* which partition [ab] == [12] is open */
short retries; /* number of times to retry failed io */
short retried; /* number of times current io retried */
+ int bytespersec; /* number of bytes per sector */
};
/* fd_softc->flags */
void fdintr __P((int));
void fdidxintr __P((void));
+int fdpulseintr __P((void *));
void fdstrategy __P((struct buf *));
int fdloaddisk __P((struct fd_softc *));
int fdgetdisklabel __P((struct fd_softc *, dev_t));
void fdfindwork __P((int));
void fdminphys __P((struct buf *));
void fdcachetoraw __P((struct fd_softc *));
+void amcachetoraw __P((struct fd_softc *));
+int amrawtocache __P((struct fd_softc *));
u_long *fdfindsync __P((u_long *, u_long *));
int fdrawtocache __P((struct fd_softc *));
+void mscachetoraw __P((struct fd_softc *));
+int msrawtocache __P((struct fd_softc *));
u_long *mfmblkencode __P((u_long *, u_long *, u_long *, int));
u_long *mfmblkdecode __P((u_long *, u_long *, u_long *, int));
+u_short *msblkdecode __P((u_short *, u_char *, int));
+u_short *msblkencode __P((u_short *, u_char *, int, u_short *));
struct dkdriver fddkdriver = { fdstrategy };
void *auxp;
{
struct fdcargs args;
+#if defined(IPL_REMAP_1) || defined(IPL_REMAP_2)
+ static struct isr isr;
+#endif
- printf(": dmabuf pa 0x%x\n", kvtop(fdc_dmap));
+ printf(": dmabuf pa 0x%x", kvtop(fdc_dmap));
+ printf(": dmabuf ka %p\n", fdc_dmap);
args.unit = 0;
args.type = fdcgetfdtype(args.unit);
continue;
config_found(dp, &args, fdcprint);
}
+#if defined(IPL_REMAP_1) || defined(IPL_REMAP_2)
+ isr.isr_intr = fdpulseintr;
+ isr.isr_ipl = 6;
+ isr.isr_mapped_ipl = IPL_BIO;
+ add_isr(&isr);
+#endif
}
int
{
struct fdcargs *ap;
struct fd_softc *sc;
+ int i;
ap = auxp;
sc = (struct fd_softc *)dp;
sc->unitmask = 1 << (3 + ap->unit);
sc->retries = FDRETRIES;
sc->stepdelay = FDSTEPDELAY;
+ sc->bytespersec = 512;
printf(" unit %d: %s %d cyl, %d head, %d sec [%d sec], 512 bytes/sec\n",
sc->hwunit, sc->type->desc, sc->type->ncylinders, FDNHEADS,
sc->type->amiga_nsectors, sc->type->msdos_nsectors);
fdsetpos(sc, 0, 0);
fdmotoroff(sc);
+ /*
+ * precalc msdos MFM and CRC
+ */
+ for (i = 0; i < 128; i++)
+ msdecode[i] = 0xff;
+ for (i = 0; i < 16; i++)
+ msdecode[msencode[i]] = i;
+ for (i = 0; i < 256; i++) {
+ mscrctab[i] = (0x1021 * (i & 0xf0)) ^ (0x1021 * (i & 0x0f)) ^
+ (0x1021 * (i >> 4));
+ }
+
/*
* enable disk related interrupts
*/
ciab.icr = CIA_ICR_FLG;
}
+#if defined(IPL_REMAP_1) || defined(IPL_REMAP_2)
+int
+fdpulseintr(arg)
+ void *arg;
+{
+ /* Is it our interrupt? */
+ if (ciab.icr & (1 << 4)) {
+ fdidxintr();
+ return 1;
+ }
+ return 0;
+}
+#endif
+
/*ARGSUSED*/
int
fdopen(dev, flags, devtype, p)
* if we were not open and we marked us so reverse that.
*/
if (error && wasopen == 0)
- sc->openpart = 0;
+ sc->openpart = -1;
return(error);
}
fdsetpos(sc, 0, 0);
if (FDTESTC(FDB_CHANGED)) {
fdmotoroff(sc);
+ FDDESELECT(sc->unitmask);
return(ENXIO);
}
}
+ FDDESELECT(sc->unitmask);
fdmotoroff(sc);
sc->type = fdcgetfdtype(sc->hwunit);
if (sc->type == NULL)
return(ENXIO);
-#ifdef not_yet
if (sc->openpart == FDMSDOSPART)
sc->nsectors = sc->type->msdos_nsectors;
else
-#endif
sc->nsectors = sc->type->amiga_nsectors;
return(0);
}
struct buf *bp;
int error, part;
- if (sc->flags & FDF_HAVELABEL)
+ if (sc->flags & FDF_HAVELABEL &&
+ sc->dkdev.dk_label->d_npartitions == (FDPART(dev) + 1))
return(0);
#ifdef FDDEBUG
printf("fdgetdisklabel()\n");
* process next buf on device queue.
* normall sequence of events:
* fdstart() -> fddmastart();
+ * fdidxintr();
* fdintr() -> fddmadone() -> fddone();
* if the track is in the cache then fdstart() will short-circuit
* to fddone() else if the track cache is dirty it will flush. If
{
int trk, error, write;
struct buf *bp, *dp;
+ int changed;
#ifdef FDDEBUG
printf("fdstart: unit %d\n", sc->hwunit);
* make sure same disk is loaded
*/
fdselunit(sc);
- if (FDTESTC(FDB_CHANGED)) {
+ changed = FDTESTC(FDB_CHANGED);
+ FDDESELECT(sc->unitmask);
+ if (changed) {
/*
* disk missing, invalidate all future io on
* this unit until re-open()'ed also invalidate
* all current io
*/
+printf("fdstart: disk changed\n");
#ifdef FDDEBUG
printf(" disk was removed invalidating all io\n");
#endif
custom.adkcon = adkmask;
}
custom.dskpt = (u_char *)kvtop(fdc_dmap);
- FDDMASTART(ndmaw, write);
+
+ /*
+ * If writing an MSDOS track, activate disk index pulse
+ * interrupt, dma will be started in the intr routine fdidxintr()
+ * Otherwise, start the DMA here.
+ */
+ if (write && sc->openpart == FDMSDOSPART) {
+ fdc_dmalen = ndmaw;
+ fdc_dmawrite = write;
+ ciab.icr = CIA_ICR_IR_SC | CIA_ICR_FLG;
+ } else {
+ FDDMASTART(ndmaw, write);
+ fdc_dmalen = 0;
+ }
#ifdef FDDEBUG
printf(" dma started\n");
* when we go to multiple disk formats, this will call type dependent
* functions
*/
+void fdcachetoraw(sc)
+ struct fd_softc *sc;
+{
+ if (sc->openpart == FDMSDOSPART)
+ mscachetoraw(sc);
+ else
+ amcachetoraw(sc);
+}
+
+/*
+ * decode raw MFM from dma into units track cache.
+ * when we go to multiple disk formats, this will call type dependent
+ * functions
+ */
+int
+fdrawtocache(sc)
+ struct fd_softc *sc;
+{
+
+ if (sc->openpart == FDMSDOSPART)
+ return(msrawtocache(sc));
+ else
+ return(amrawtocache(sc));
+}
+
void
-fdcachetoraw(sc)
+amcachetoraw(sc)
struct fd_softc *sc;
{
static u_long mfmnull[4];
*crp &= 0x7fffffff; /* clock bit correction */
else if ((*crp & 0x40000000) == 0)
*crp |= 0x80000000;
- }
+ }
*rp = 0xaaa80000;
if (*(rp - 1) & 0x1)
*rp &= 0x7fffffff;
return(NULL);
}
-/*
- * decode raw MFM from dma into units track cache.
- * when we go to multiple disk formats, this will call type dependent
- * functions
- */
int
-fdrawtocache(sc)
+amrawtocache(sc)
struct fd_softc *sc;
{
u_long mfmnull[4];
return(0);
}
+void
+mscachetoraw(sc)
+ struct fd_softc *sc;
+{
+ u_short *rp, *erp, crc;
+ u_char *cp, tb[5];
+ int sec, i;
+
+ rp = (u_short *)fdc_dmap;
+ erp = rp + sc->type->nwritew;
+ cp = sc->cachep;
+
+ /*
+ * initial track filler (828 * GAP1)
+ */
+ for (i = 0; i < sc->type->gap; i++) {
+ *rp++ = FDMFMGAP1;
+ *rp++ = FDMFMGAP1;
+ }
+
+ for (sec = 0; sec < sc->nsectors; sec++) {
+
+ /*
+ * leading sector gap
+ * (12 * GAP2) + (3 * SYNC)
+ */
+ for (i = 0; i < 12; i++)
+ *rp++ = FDMFMGAP2;
+ *rp++ = FDMFMSYNC;
+ *rp++ = FDMFMSYNC;
+ *rp++ = FDMFMSYNC;
+
+ /*
+ * sector information
+ * (ID) + track + side + sector + sector size + CRC16
+ */
+ *rp++ = FDMFMID;
+ tb[0] = sc->cachetrk / FDNHEADS;
+ tb[1] = sc->cachetrk % FDNHEADS;
+ tb[2] = sec + 1;
+ i = sc->bytespersec;
+ tb[3] = i < 256 ? 0 : (i < 512 ? 1 : (i < 1024 ? 2 : 3));
+ rp = msblkencode(rp, tb, 4, &crc);
+ tb[0] = crc >> 8;
+ tb[1] = crc & 0xff;
+ tb[2] = 0x4e; /* GAP1 decoded */
+ rp = msblkencode(rp, tb, 3, 0);
+
+ /*
+ * sector info/data gap
+ * (22 * GAP1) + (12 * GAP2) + (3 * SYNC)
+ */
+ for (i = 0; i < 21; i++)
+ *rp++ = FDMFMGAP1;
+ for (i = 0; i < 12; i++)
+ *rp++ = FDMFMGAP2;
+ *rp++ = FDMFMSYNC;
+ *rp++ = FDMFMSYNC;
+ *rp++ = FDMFMSYNC;
+
+ /*
+ * sector data
+ * (DATA) + ...data... + CRC16
+ */
+ *rp++ = FDMFMDATA;
+ rp = msblkencode(rp, cp, sc->bytespersec, &crc);
+ cp += sc->bytespersec;
+ tb[0] = crc >> 8;
+ tb[1] = crc & 0xff;
+ tb[2] = 0x4e; /* GAP3 decoded */
+ rp = msblkencode(rp, tb, 3, 0);
+
+ /*
+ * trailing sector gap
+ * (80 * GAP3)
+ */
+ for (i = 0; i < 79; i++)
+ *rp++ = FDMFMGAP3;
+ }
+
+ /*
+ * fill rest of track with GAP3
+ */
+ while (rp != erp)
+ *rp++ = FDMFMGAP3;
+
+}
+
+int
+msrawtocache(sc)
+ struct fd_softc *sc;
+{
+ u_short *rp, *srp, *erp;
+ u_char tb[5], *cp;
+ int ct, sec, retry;
+
+ srp = rp = (u_short *)fdc_dmap;
+ erp = rp + sc->type->nreadw;
+ cp = sc->cachep;
+
+ for (ct = 0; ct < sc->nsectors; ct++) {
+ retry = 1;
+ do {
+ /*
+ * skip leading gap to sync
+ */
+ if ((rp = (u_short *)fdfindsync((u_long *)rp, (u_long *)erp)) == NULL) {
+#ifdef DIAGNOSTIC
+ printf("%s: corrupted track (%d) data.\n",
+ sc->sc_dv.dv_xname, sc->cachetrk);
+#endif
+ return(-1);
+ }
+
+ /*
+ * Grab sector info
+ */
+ if (*rp++ != FDMFMID)
+ continue;
+ rp = msblkdecode(rp, tb, 4);
+#ifdef FDDEBUG
+ printf("sector id: sector %d, track %d, side %d,"
+ "bps %d\n", tb[2], tb[0], tb[1], 128 << tb[3]);
+#endif
+ if ((tb[0] * FDNHEADS + tb[1]) != sc->cachetrk ||
+ tb[2] > sc->nsectors)
+ continue;
+
+ sec = tb[2];
+ sc->bytespersec = 128 << tb[3];
+ rp += 2; /* skip CRC-16 */
+
+ /*
+ * skip gap and read in data
+ */
+ if ((rp = (u_short *)fdfindsync((u_long *)rp, (u_long *)erp)) == NULL)
+ return(-1);
+ if (*rp++ != FDMFMDATA)
+ continue;
+ rp = msblkdecode(rp, cp + ((sec-1) * sc->bytespersec),
+ sc->bytespersec);
+ rp += 2; /* skip CRC-16 */
+
+ retry = 0;
+ } while (retry);
+ }
+ return(0);
+}
+
/*
* encode len longwords of `dp' data in amiga mfm block format (`rp')
* this format specified that the odd bits are at current pos and even
return(rp + len);
}
+/*
+ * decode len words in standard MFM format to len bytes
+ * of data.
+ */
+u_short *
+msblkdecode(rp, cp, len)
+ u_short *rp;
+ u_char *cp;
+ int len;
+{
+ while (len--) {
+ *cp++ = msdecode[*rp & 0x7f] |
+ (msdecode[(*rp >> 8) & 0x7f] << 4);
+ rp++;
+ }
+
+ return(rp);
+}
+
+/*
+ * encode len bytes of data into len words in standard MFM format.
+ * If a pointer is supplied for crc, calculate the CRC-16 of the data
+ * as well.
+ */
+u_short *
+msblkencode(rp, cp, len, crc)
+ u_short *rp;
+ u_char *cp;
+ int len;
+ u_short *crc;
+{
+ u_short td;
+ u_short mycrc;
+
+ /* preload crc for header (4 bytes)
+ * or data (anything else)
+ */
+ mycrc = (len == 4) ? 0xb230 : 0xe295;
+
+ while (len--) {
+ td = (msencode[*cp >> 4] << 8) | msencode[*cp & 0x0f];
+
+ /* Check for zeros in top bit of encode and bottom
+ * bit of previous encode. if so, slap a one in betweem
+ * them.
+ */
+ if ((td & 0x140) == 0)
+ td |= 0x80;
+ if ((td & 0x4000) == 0 && (rp[-1] & 1) == 0)
+ td |= 0x8000;
+
+ *rp++ = td;
+
+ /*
+ * calc crc if requested
+ */
+ if (crc)
+ mycrc = (mycrc << 8) ^ mscrctab[*cp ^ (mycrc >> 8)];
+
+ cp++;
+ }
+
+ if (crc)
+ *crc = mycrc;
+
+ return(rp);
+}
+
int
fddump(dev, blkno, va, size)
dev_t dev;