aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorJoerg Wunsch <joerg@FreeBSD.org>1995-01-06 15:20:00 +0000
committerJoerg Wunsch <joerg@FreeBSD.org>1995-01-06 15:20:00 +0000
commitdc5df763e473f6204f45e438a84477b0f66668ed (patch)
tree59e85172d0f0879e0d6be3b17ccb0f10ddd40c33 /sys
parent123bcf5fda4007c62993b97e09c911ba5da48dec (diff)
Notes
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/fdc/fdc.c507
-rw-r--r--sys/dev/ic/nec765.h7
-rw-r--r--sys/i386/isa/fd.c507
-rw-r--r--sys/i386/isa/fdc.h17
-rw-r--r--sys/i386/isa/ic/nec765.h7
-rw-r--r--sys/isa/fd.c507
-rw-r--r--sys/isa/fdc.h17
-rw-r--r--sys/isa/ic/nec765.h7
8 files changed, 1139 insertions, 437 deletions
diff --git a/sys/dev/fdc/fdc.c b/sys/dev/fdc/fdc.c
index 241cf3b4af9b..e9c50002d600 100644
--- a/sys/dev/fdc/fdc.c
+++ b/sys/dev/fdc/fdc.c
@@ -5,11 +5,12 @@
* This code is derived from software contributed to Berkeley by
* Don Ahn.
*
- * Portions Copyright (c) 1993, 1994 by
+ * Portions Copyright (c) 1993, 1994, 1995 by
* jc@irbs.UUCP (John Capo)
* vak@zebub.msk.su (Serge Vakulenko)
* ache@astral.msk.su (Andrew A. Chernov)
* joerg_wunsch@uriah.sax.de (Joerg Wunsch)
+ * dufault@hda.com (Peter Dufault)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -40,7 +41,7 @@
* SUCH DAMAGE.
*
* from: @(#)fd.c 7.4 (Berkeley) 5/25/91
- * $Id: fd.c,v 1.45 1994/11/30 12:04:28 jkh Exp $
+ * $Id: fd.c,v 1.46 1994/12/04 20:22:19 joerg Exp $
*
*/
@@ -76,6 +77,7 @@
#include <i386/isa/fdreg.h>
#include <i386/isa/fdc.h>
#include <i386/isa/rtc.h>
+#include <machine/stdarg.h>
#if NFT > 0
#include <sys/ftape.h>
#include <i386/isa/ftreg.h>
@@ -164,6 +166,11 @@ fd_goaway(struct kern_devconf *kdc, int force)
*/
#define id_physid id_scsiid
+/* error returns for fd_cmd() */
+#define FD_FAILED -1
+#define FD_NOT_VALID -2
+#define FDC_ERRMAX 100 /* do not log more */
+
#define NUMTYPES 14
#define NUMDENS (NUMTYPES - 6)
@@ -228,6 +235,7 @@ struct fd_data {
#define FD_MOTOR_WAIT 0x08 /* motor coming up */
int skip;
int hddrv;
+#define FD_NO_TRACK -2
int track; /* where we think the head is */
int options; /* user configurable options, see ioctl_fd.h */
int dkunit; /* disk stats unit number */
@@ -341,6 +349,136 @@ fdc_externalize(struct proc *p, struct kern_devconf *kdc, void *userp, size_t le
return isa_externalize(fdcdevs[kdc->kdc_unit], userp, &len);
}
+static int
+fdc_err(fdcu_t fdcu, const char *s)
+{
+ fdc_data[fdcu].fdc_errs++;
+ if(fdc_data[fdcu].fdc_errs < FDC_ERRMAX)
+ printf("fdc%d: %s: ", fdcu, s);
+ else if(fdc_data[fdcu].fdc_errs == FDC_ERRMAX)
+ printf("fdc%d: too many errors, not logging any more\n",
+ fdcu);
+
+ return FD_FAILED;
+}
+
+/*
+ * fd_cmd: Send a command to the chip. Takes a varargs with this structure:
+ * Unit number,
+ * # of output bytes, output bytes as ints ...,
+ * # of input bytes, input bytes as ints ...
+ */
+
+int
+fd_cmd(fdcu_t fdcu, int n_out, ...)
+{
+ u_char cmd;
+ int n_in;
+ int n;
+ va_list ap;
+
+ va_start(ap, n_out);
+ cmd = (u_char)(va_arg(ap, int));
+ va_end(ap);
+ va_start(ap, n_out);
+ for (n = 0; n < n_out; n++)
+ {
+ if (out_fdc(fdcu, va_arg(ap, int)) < 0)
+ {
+ char msg[50];
+ sprintf(msg,
+ "cmd %x failed at out byte %d of %d\n",
+ cmd, n + 1, n_out);
+ return fdc_err(fdcu, msg);
+ }
+ }
+ n_in = va_arg(ap, int);
+ for (n = 0; n < n_in; n++)
+ {
+ int *ptr = va_arg(ap, int *);
+ if (fd_in(fdcu, ptr) < 0)
+ {
+ char msg[50];
+ sprintf(msg,
+ "cmd %02x failed at in byte %d of %d\n",
+ cmd, n + 1, n_in);
+ return fdc_err(fdcu, msg);
+ }
+ }
+
+ return 0;
+}
+
+int
+fd_sense_drive_status(fdc_p fdc, int *st3p)
+{
+ int st3;
+
+ if (fd_cmd(fdc->fdcu, 2, NE7CMD_SENSED, fdc->fdu, 1, &st3))
+ {
+ return fdc_err(fdc->fdcu, "Sense Drive Status failed.\n");
+ }
+ if (st3p)
+ *st3p = st3;
+
+ return 0;
+}
+
+int
+fd_sense_int(fdc_p fdc, int *st0p, int *cylp)
+{
+ int st0, cyl;
+
+ int ret = fd_cmd(fdc->fdcu, 1, NE7CMD_SENSEI, 1, &st0);
+
+ if (ret)
+ {
+ (void)fdc_err(fdc->fdcu,
+ "sense intr err reading stat reg 0\n");
+ return ret;
+ }
+
+ if (st0p)
+ *st0p = st0;
+
+ if ((st0 & NE7_ST0_IC) == NE7_ST0_IC_IV)
+ {
+ /*
+ * There doesn't seem to have been an interrupt.
+ */
+ return FD_NOT_VALID;
+ }
+
+ if (fd_in(fdc->fdcu, &cyl) < 0)
+ {
+ return fdc_err(fdc->fdcu, "can't get cyl num\n");
+ }
+
+ if (cylp)
+ *cylp = cyl;
+
+ return 0;
+}
+
+
+int
+fd_read_status(fdc_p fdc, int fdsu)
+{
+ int i, ret;
+ for (i = 0; i < 7; i++)
+ {
+ if ((ret = fd_in(fdc->fdcu, fdc->status + i)))
+ break;
+ }
+
+ if (ret == 0)
+ fdc->flags |= FDC_STAT_VALID;
+ else
+ fdc->flags &= ~FDC_STAT_VALID;
+
+ return ret;
+}
+
/****************************************************************************/
/* autoconfiguration stuff */
/****************************************************************************/
@@ -348,12 +486,12 @@ struct isa_driver fdcdriver = {
fdprobe, fdattach, "fdc",
};
+
/*
* probe for existance of controller
*/
static int
-fdprobe(dev)
- struct isa_device *dev;
+fdprobe(struct isa_device *dev)
{
fdcu_t fdcu = dev->id_unit;
if(fdc_data[fdcu].flags & FDC_ATTACHED)
@@ -371,12 +509,12 @@ fdprobe(dev)
outb(dev->id_iobase+FDOUT, FDO_FRST);
/* see if it can handle a command */
- if (out_fdc(fdcu, NE7CMD_SPECIFY) < 0)
+ if (fd_cmd(fdcu,
+ 3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
+ 0))
{
return(0);
}
- out_fdc(fdcu, NE7_SPEC_1(3, 240));
- out_fdc(fdcu, NE7_SPEC_2(2, 0));
return (IO_FDCSIZE);
}
@@ -384,16 +522,16 @@ fdprobe(dev)
* wire controller into system, look for floppy units
*/
static int
-fdattach(dev)
- struct isa_device *dev;
+fdattach(struct isa_device *dev)
{
unsigned fdt;
fdu_t fdu;
fdcu_t fdcu = dev->id_unit;
fdc_p fdc = fdc_data + fdcu;
fd_p fd;
- int fdsu, st0, i;
+ int fdsu, st0, st3, i;
struct isa_device *fdup;
+ int ic_type = 0;
fdc_registerdev(dev);
@@ -403,7 +541,7 @@ fdattach(dev)
fdc->state = DEVIDLE;
/* reset controller, turn motor off, clear fdout mirror reg */
outb(fdc->baseport + FDOUT, ((fdc->fdout = 0)));
- printf("fdc%d:", fdcu);
+ printf("fdc%d: ", fdcu);
/* check for each floppy drive */
for (fdup = isa_biotab_fdc; fdup->id_driver != 0; fdup++) {
@@ -414,7 +552,7 @@ fdattach(dev)
if (fdu >= (NFD+NFT))
continue;
fdsu = fdup->id_physid;
- /* look up what bios thinks we have */
+ /* look up what bios thinks we have */
switch (fdu) {
case 0: fdt = (rtcin(RTC_FDISKETTE) & 0xf0);
break;
@@ -445,18 +583,51 @@ fdattach(dev)
/* select it */
set_motor(fdcu, fdsu, TURNON);
DELAY(1000000); /* 1 sec */
- out_fdc(fdcu, NE7CMD_SENSED);
- out_fdc(fdcu, fdsu);
- if(in_fdc(fdcu) & NE7_ST3_T0) {
+
+ if (ic_type == 0 &&
+ fd_cmd(fdcu, 1, NE7CMD_VERSION, 1, &ic_type) == 0)
+ {
+ ic_type = (u_char)ic_type;
+ switch( ic_type ) {
+ case 0x80:
+ printf("(NEC 765)");
+ fdc->fdct = FDC_NE765;
+ break;
+ case 0x81:
+ printf("(Intel 82077)");
+ fdc->fdct = FDC_I82077;
+ break;
+ case 0x90:
+ printf("(NEC 72065B)");
+ fdc->fdct = FDC_NE72065;
+ break;
+ default:
+ printf("(unknown IC type %02x)", ic_type);
+ fdc->fdct = FDC_UNKNOWN;
+ break;
+ }
+ }
+ if ((fd_cmd(fdcu, 2, NE7CMD_SENSED, fdsu, 1, &st3) == 0) &&
+ (st3 & NE7_ST3_T0)) {
/* if at track 0, first seek inwards */
- out_fdc(fdcu, NE7CMD_SEEK); /* seek some steps... */
- out_fdc(fdcu, fdsu);
- out_fdc(fdcu, 10);
+ /* seek some steps: */
+ (void)fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0);
DELAY(300000); /* ...wait a moment... */
- out_fdc(fdcu, NE7CMD_SENSEI); /* make ctrlr happy */
- (void)in_fdc(fdcu);
- (void)in_fdc(fdcu);
+ (void)fd_sense_int(fdc, 0, 0); /* make ctrlr happy */
+ }
+
+ /* If we're at track 0 first seek inwards. */
+ if ((fd_sense_drive_status(fdc, &st3) == 0) &&
+ (st3 & NE7_ST3_T0)) {
+ /* Seek some steps... */
+ if (fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) {
+ /* ...wait a moment... */
+ DELAY(300000);
+ /* make ctrlr happy: */
+ (void)fd_sense_int(fdc, 0, 0);
+ }
}
+
for(i = 0; i < 2; i++) {
/*
* we must recalibrate twice, just in case the
@@ -464,18 +635,16 @@ fdattach(dev)
* FDCs still barf when attempting to recalibrate
* more than 77 steps
*/
- out_fdc(fdcu, NE7CMD_RECAL); /* go back to 0 */
- out_fdc(fdcu, fdsu);
- /* a second being enough for full stroke seek */
- DELAY(i == 0? 1000000: 300000);
+ /* go back to 0: */
+ if (fd_cmd(fdcu, 2, NE7CMD_RECAL, fdsu, 0) == 0) {
+ /* a second being enough for full stroke seek*/
+ DELAY(i == 0? 1000000: 300000);
- /* anything responding? */
- out_fdc(fdcu, NE7CMD_SENSEI);
- st0 = in_fdc(fdcu);
- (void)in_fdc(fdcu);
-
- if ((st0 & NE7_ST0_EC) == 0)
- break; /* already probed succesfully */
+ /* anything responding? */
+ if (fd_sense_int(fdc, &st0, 0) == 0 &&
+ (st0 & NE7_ST0_EC) == 0)
+ break; /* already probed succesfully */
+ }
}
set_motor(fdcu, fdsu, TURNOFF);
@@ -483,7 +652,7 @@ fdattach(dev)
if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */
continue;
- fd->track = -2;
+ fd->track = FD_NO_TRACK;
fd->fdc = fdc;
fd->fdsu = fdsu;
fd->options = 0;
@@ -530,8 +699,7 @@ fdattach(dev)
}
int
-fdsize(dev)
- dev_t dev;
+fdsize(dev_t dev)
{
return(0);
}
@@ -541,10 +709,7 @@ fdsize(dev)
/* remember to not deselect the drive we're working on */
/****************************************************************************/
static void
-set_motor(fdcu, fdsu, turnon)
- fdcu_t fdcu;
- int fdsu;
- int turnon;
+set_motor(fdcu_t fdcu, int fdsu, int turnon)
{
int fdout = fdc_data[fdcu].fdout;
int needspecify = 0;
@@ -572,13 +737,14 @@ set_motor(fdcu, fdsu, turnon)
if(needspecify) {
/*
+ * XXX
* special case: since we have just woken up the FDC
* from its sleep, we silently assume the command will
* be accepted, and do not test for a timeout
*/
- out_fdc(fdcu, NE7CMD_SPECIFY);
- out_fdc(fdcu, NE7_SPEC_1(3, 240));
- out_fdc(fdcu, NE7_SPEC_2(2, 0));
+ (void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY,
+ NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
+ 0);
}
}
@@ -614,8 +780,7 @@ fd_motor_on(void *arg1)
}
static void
-fd_turnon(fdu)
- fdu_t fdu;
+fd_turnon(fdu_t fdu)
{
fd_p fd = fd_data + fdu;
if(!(fd->flags & FD_MOTOR))
@@ -627,8 +792,7 @@ fd_turnon(fdu)
}
static void
-fdc_reset(fdc)
- fdc_p fdc;
+fdc_reset(fdc_p fdc)
{
fdcu_t fdcu = fdc->fdcu;
@@ -643,26 +807,26 @@ fdc_reset(fdc)
outb(fdc->baseport + FDOUT, fdc->fdout);
TRACE1("[0x%x->FDOUT]", fdc->fdout);
- /* after a reset, silently believe the FDC will accept commands */
- out_fdc(fdcu, NE7CMD_SPECIFY);
- out_fdc(fdcu, NE7_SPEC_1(3, 240));
- out_fdc(fdcu, NE7_SPEC_2(2, 0));
+ /* XXX after a reset, silently believe the FDC will accept commands */
+ (void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY,
+ NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
+ 0);
}
/****************************************************************************/
/* fdc in/out */
/****************************************************************************/
int
-in_fdc(fdcu)
- fdcu_t fdcu;
+in_fdc(fdcu_t fdcu)
{
int baseport = fdc_data[fdcu].baseport;
int i, j = 100000;
while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM))
!= (NE7_DIO|NE7_RQM) && j-- > 0)
- if (i == NE7_RQM) return -1;
+ if (i == NE7_RQM)
+ return fdc_err(fdcu, "ready for output in input");
if (j <= 0)
- return(-1);
+ return fdc_err(fdcu, "input ready timeout");
#ifdef DEBUG
i = inb(baseport+FDDATA);
TRACE1("[FDDATA->0x%x]", (unsigned char)i);
@@ -672,10 +836,35 @@ in_fdc(fdcu)
#endif
}
+/*
+ * fd_in: Like in_fdc, but allows you to see if it worked.
+ */
int
-out_fdc(fdcu, x)
- fdcu_t fdcu;
- int x;
+fd_in(fdcu_t fdcu, int *ptr)
+{
+ int baseport = fdc_data[fdcu].baseport;
+ int i, j = 100000;
+ while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM))
+ != (NE7_DIO|NE7_RQM) && j-- > 0)
+ if (i == NE7_RQM)
+ return fdc_err(fdcu, "ready for output in input");
+ if (j <= 0)
+ return fdc_err(fdcu, "input ready timeout");
+#ifdef DEBUG
+ i = inb(baseport+FDDATA);
+ TRACE1("[FDDATA->0x%x]", (unsigned char)i);
+ *ptr = i;
+ return 0;
+#else
+ i = inb(baseport+FDDATA);
+ if (ptr)
+ *ptr = i;
+ return 0;
+#endif
+}
+
+int
+out_fdc(fdcu_t fdcu, int x)
{
int baseport = fdc_data[fdcu].baseport;
int i;
@@ -683,12 +872,12 @@ out_fdc(fdcu, x)
/* Check that the direction bit is set */
i = 100000;
while ((inb(baseport+FDSTS) & NE7_DIO) && i-- > 0);
- if (i <= 0) return (-1); /* Floppy timed out */
+ if (i <= 0) return fdc_err(fdcu, "direction bit not set");
/* Check that the floppy controller is ready for a command */
i = 100000;
while ((inb(baseport+FDSTS) & NE7_RQM) == 0 && i-- > 0);
- if (i <= 0) return (-1); /* Floppy timed out */
+ if (i <= 0) return fdc_err(fdcu, "output ready timeout");
/* Send the command and return */
outb(baseport+FDDATA, x);
@@ -700,9 +889,7 @@ out_fdc(fdcu, x)
/* fdopen/fdclose */
/****************************************************************************/
int
-Fdopen(dev, flags)
- dev_t dev;
- int flags;
+Fdopen(dev_t dev, int flags)
{
fdu_t fdu = FDUNIT(minor(dev));
int type = FDTYPE(minor(dev));
@@ -777,16 +964,23 @@ Fdopen(dev, flags)
set_motor(fdc->fdcu, fd_data[fdu].fdsu, TURNON);
if (flags & FWRITE) {
- /* Check to make sure the diskette */
- /* is writable */
- out_fdc(fdc->fdcu, NE7CMD_SENSED);
- out_fdc(fdc->fdcu, fdu);
- st3 = in_fdc(fdc->fdcu);
- if(st3 & NE7_ST3_WP) {
- printf("fd%d: write protected\n", fdu);
- set_motor(fdc->fdcu, fd_data[fdu].fdsu, TURNOFF);
- return(EPERM);
+ /*
+ * Check to make sure the diskette is writable:
+ */
+ int err = 0;
+
+ if (fd_sense_drive_status(fdc, &st3) != 0)
+ err = EIO;
+ else if ( (st3 & NE7_ST3_WP) )
+ {
+ printf("fd%d: drive is write protected.\n", fdu);
+ err = ENXIO;
}
+
+ if (err) {
+ set_motor(fdc->fdcu, fd_data[fdu].fdsu, TURNOFF);
+ return err;
+ }
}
set_motor(fdc->fdcu, fd_data[fdu].fdsu, TURNOFF);
@@ -798,9 +992,7 @@ Fdopen(dev, flags)
}
int
-fdclose(dev, flags)
- dev_t dev;
- int flags;
+fdclose(dev_t dev, int flags)
{
fdu_t fdu = FDUNIT(minor(dev));
@@ -853,7 +1045,8 @@ fdstrategy(struct buf *bp)
#endif
if (!(bp->b_flags & B_FORMAT)) {
if ((fdu >= NFD) || (bp->b_blkno < 0)) {
- printf("fdstrat: fdu = %d, blkno = %lu, bcount = %ld\n",
+ printf(
+ "fdstrat: fd%d: bad request blkno = %lu, bcount = %ld\n",
fdu, (u_long)bp->b_blkno, bp->b_bcount);
bp->b_error = EINVAL;
bp->b_flags |= B_ERROR;
@@ -903,8 +1096,7 @@ bad:
* will pick up our work when the present work completes *
\***************************************************************/
static void
-fdstart(fdcu)
- fdcu_t fdcu;
+fdstart(fdcu_t fdcu)
{
int s;
@@ -1005,9 +1197,7 @@ fdintr(fdcu_t fdcu)
* if it returns a non zero value, it should be called again immediatly *
\***********************************************************************/
static int
-fdstate(fdcu, fdc)
- fdcu_t fdcu;
- fdc_p fdc;
+fdstate(fdcu_t fdcu, fdc_p fdc)
{
int read, format, head, sec = 0, i = 0, sectrac, st0, cyl, st3;
unsigned long blknum;
@@ -1092,7 +1282,9 @@ fdstate(fdcu, fdc)
fdc->state = SEEKCOMPLETE;
break;
}
- if(out_fdc(fdcu, NE7CMD_SEEK) < 0) /* Seek function */
+ if (fd_cmd(fdcu, 3, NE7CMD_SEEK,
+ fd->fdsu, bp->b_cylin * fd->ft->steptrac,
+ 0))
{
/*
* seek command not accepted, looks like
@@ -1101,9 +1293,7 @@ fdstate(fdcu, fdc)
fdc->retry = 6; /* try a reset */
return(retrier(fdcu));
}
- out_fdc(fdcu, fd->fdsu); /* Drive number */
- out_fdc(fdcu, bp->b_cylin * fd->ft->steptrac);
- fd->track = -2;
+ fd->track = FD_NO_TRACK;
fdc->state = SEEKWAIT;
return(0); /* will return later */
case SEEKWAIT:
@@ -1113,37 +1303,63 @@ fdstate(fdcu, fdc)
return(0); /* will return later */
case SEEKCOMPLETE : /* SEEK DONE, START DMA */
/* Make sure seek really happened*/
- if(fd->track == -2)
+ if(fd->track == FD_NO_TRACK)
{
int descyl = bp->b_cylin * fd->ft->steptrac;
do {
- out_fdc(fdcu, NE7CMD_SENSEI);
- st0 = in_fdc(fdcu);
- cyl = in_fdc(fdcu);
/*
- * if this was a "ready changed" interrupt,
- * fetch status again (can happen after
- * enabling controller from reset state)
+ * This might be a "ready changed" interrupt,
+ * which cannot really happen since the
+ * RDY pin is hardwired to + 5 volts. This
+ * generally indicates a "bouncing" intr
+ * line, so do one of the following:
+ *
+ * When running on an enhanced FDC that is
+ * known to not go stuck after responding
+ * with INVALID, fetch all interrupt states
+ * until seeing either an INVALID or a
+ * real interrupt condition.
+ *
+ * When running on a dumb old NE765, give
+ * up immediately. The controller will
+ * provide up to four dummy RC interrupt
+ * conditions right after reset (for the
+ * corresponding four drives), so this is
+ * our only chance to get notice that it
+ * was not the FDC that caused the interrupt.
*/
+ if (fd_sense_int(fdc, &st0, &cyl)
+ == FD_NOT_VALID)
+ return 0;
+ if(fdc->fdct == FDC_NE765
+ && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC)
+ return 0; /* hope for a real intr */
} while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
+
if (0 == descyl)
{
+ int failed = 0;
/*
* seek to cyl 0 requested; make sure we are
* really there
*/
- out_fdc(fdcu, NE7CMD_SENSED);
- out_fdc(fdcu, fdu);
- st3 = in_fdc(fdcu);
+ if (fd_sense_drive_status(fdc, &st3))
+ failed = 1;
if ((st3 & NE7_ST3_T0) == 0) {
printf(
"fd%d: Seek to cyl 0, but not really there (ST3 = %b)\n",
fdu, st3, NE7_ST3BITS);
+ failed = 1;
+ }
+
+ if (failed)
+ {
if(fdc->retry < 3)
fdc->retry = 3;
return(retrier(fdcu));
}
}
+
if (cyl != descyl)
{
printf(
@@ -1170,14 +1386,12 @@ fdstate(fdcu, fdc)
if(format || !read)
{
/* make sure the drive is writable */
- if(out_fdc(fdcu, NE7CMD_SENSED) < 0)
+ if(fd_sense_drive_status(fdc, &st3) != 0)
{
/* stuck controller? */
fdc->retry = 6; /* reset the beast */
return(retrier(fdcu));
}
- out_fdc(fdcu, fdu);
- st3 = in_fdc(fdcu);
if(st3 & NE7_ST3_WP)
{
/*
@@ -1202,48 +1416,56 @@ fdstate(fdcu, fdc)
if(format)
{
/* formatting */
- if(out_fdc(fdcu, NE7CMD_FORMAT) < 0)
+ if(fd_cmd(fdcu, 6,
+ NE7CMD_FORMAT,
+ head << 2 | fdu,
+ finfo->fd_formb_secshift,
+ finfo->fd_formb_nsecs,
+ finfo->fd_formb_gaplen,
+ finfo->fd_formb_fillbyte,
+ 0))
{
/* controller fell over */
fdc->retry = 6;
return(retrier(fdcu));
}
- out_fdc(fdcu, head << 2 | fdu);
- out_fdc(fdcu, finfo->fd_formb_secshift);
- out_fdc(fdcu, finfo->fd_formb_nsecs);
- out_fdc(fdcu, finfo->fd_formb_gaplen);
- out_fdc(fdcu, finfo->fd_formb_fillbyte);
}
else
{
- if ((read && out_fdc(fdcu, NE7CMD_READ) < 0)
- || (!read /* i.e., write */
- && out_fdc(fdcu, NE7CMD_WRITE) < 0))
+ if (fd_cmd(fdcu, 9,
+ (read ? NE7CMD_READ : NE7CMD_WRITE),
+ head << 2 | fdu, /* head & unit */
+ fd->track, /* track */
+ head,
+ sec, /* sector + 1 */
+ fd->ft->secsize, /* sector size */
+ sectrac, /* sectors/track */
+ fd->ft->gap, /* gap size */
+ fd->ft->datalen, /* data length */
+ 0))
{
/* the beast is sleeping again */
fdc->retry = 6;
return(retrier(fdcu));
}
- out_fdc(fdcu, head << 2 | fdu); /* head & unit */
- out_fdc(fdcu, fd->track); /* track */
- out_fdc(fdcu, head);
- out_fdc(fdcu, sec); /* sector XXX +1? */
- out_fdc(fdcu, fd->ft->secsize); /* sector size */
- out_fdc(fdcu, sectrac); /* sectors/track */
- out_fdc(fdcu, fd->ft->gap); /* gap size */
- out_fdc(fdcu, fd->ft->datalen); /* data length */
}
fdc->state = IOCOMPLETE;
timeout(fd_timeout, (caddr_t)fdcu, hz);
return(0); /* will return later */
case IOCOMPLETE: /* IO DONE, post-analyze */
untimeout(fd_timeout, (caddr_t)fdcu);
- for(i=0;i<7;i++)
+
+ if (fd_read_status(fdc, fd->fdsu))
{
- fdc->status[i] = in_fdc(fdcu);
- }
+ if (fdc->retry < 6)
+ fdc->retry = 6; /* force a reset */
+ return retrier(fdcu);
+ }
+
fdc->state = IOTIMEDOUT;
+
/* FALLTHROUGH */
+
case IOTIMEDOUT:
isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip,
format ? bp->b_bcount : fdblk, fdc->dmachan);
@@ -1299,13 +1521,14 @@ fdstate(fdcu, fdc)
fdc->state = STARTRECAL;
break;
case STARTRECAL:
- if(out_fdc(fdcu, NE7CMD_RECAL) < 0) /* Recalibrate Function */
+ if(fd_cmd(fdcu,
+ 2, NE7CMD_RECAL, fdu,
+ 0)) /* Recalibrate Function */
{
/* arrgl */
fdc->retry = 6;
return(retrier(fdcu));
}
- out_fdc(fdcu, fdu);
fdc->state = RECALWAIT;
return(0); /* will return later */
case RECALWAIT:
@@ -1315,14 +1538,14 @@ fdstate(fdcu, fdc)
return(0); /* will return later */
case RECALCOMPLETE:
do {
- out_fdc(fdcu, NE7CMD_SENSEI);
- st0 = in_fdc(fdcu);
- cyl = in_fdc(fdcu);
/*
- * if this was a "ready changed" interrupt,
- * fetch status again (can happen after
- * enabling controller from reset state)
+ * See SEEKCOMPLETE for a comment on this:
*/
+ if (fd_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID)
+ return 0;
+ if(fdc->fdct == FDC_NE765
+ && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC)
+ return 0; /* hope for a real intr */
} while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
if ((st0 & NE7_ST0_IC) != NE7_ST0_IC_NT || cyl != 0)
{
@@ -1357,22 +1580,15 @@ fdstate(fdcu, fdc)
fdc->state = STARTRECAL;
return(1); /* will return immediatly */
default:
- printf("Unexpected FD int->");
- if(out_fdc(fdcu, NE7CMD_SENSEI) < 0)
+ printf("fdc%d: Unexpected FD int->", fdcu);
+ if (fd_sense_int(fdc, &st0, &cyl) != 0)
{
printf("[controller is dead now]\n");
return(0);
}
- st0 = in_fdc(fdcu);
- cyl = in_fdc(fdcu);
printf("ST0 = %x, PCN = %x\n", st0, cyl);
- out_fdc(fdcu, NE7CMD_READID);
- out_fdc(fdcu, fd->fdsu);
- for(i=0;i<7;i++) {
- fdc->status[i] = in_fdc(fdcu);
- }
- if(fdc->status[0] != -1)
- printf("intr status :%lx %lx %lx %lx %lx %lx %lx\n",
+ if (fd_read_status(fdc, fd->fdsu) == 0)
+ printf("FDC status :%lx %lx %lx %lx %lx %lx %lx\n",
fdc->status[0],
fdc->status[1],
fdc->status[2],
@@ -1381,7 +1597,7 @@ fdstate(fdcu, fdc)
fdc->status[5],
fdc->status[6] );
else
- printf("FDC timed out\n");
+ printf("No status available\n");
return(0);
}
return(1); /* Come back immediatly to new state */
@@ -1423,11 +1639,18 @@ retrier(fdcu)
fdc->fd->skip / DEV_BSIZE,
(struct disklabel *)NULL);
bp->b_dev = sav_b_dev;
- printf(" (ST0 %b ", fdc->status[0], NE7_ST0BITS);
- printf(" ST1 %b ", fdc->status[1], NE7_ST1BITS);
- printf(" ST2 %b ", fdc->status[2], NE7_ST2BITS);
- printf("cyl %ld hd %ld sec %ld)\n",
- fdc->status[3], fdc->status[4], fdc->status[5]);
+ if (fdc->flags & FDC_STAT_VALID)
+ {
+ printf(
+ " (ST0 %b ST1 %b ST2 %b cyl %ld hd %ld sec %ld)\n",
+ fdc->status[0], NE7_ST0BITS,
+ fdc->status[1], NE7_ST1BITS,
+ fdc->status[2], NE7_ST2BITS,
+ fdc->status[3], fdc->status[4],
+ fdc->status[5]);
+ }
+ else
+ printf(" (No status)\n");
}
bp->b_flags |= B_ERROR;
bp->b_error = EIO;
diff --git a/sys/dev/ic/nec765.h b/sys/dev/ic/nec765.h
index 9f93b705efe4..810e825bd66e 100644
--- a/sys/dev/ic/nec765.h
+++ b/sys/dev/ic/nec765.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)nec765.h 7.1 (Berkeley) 5/9/91
- * $Id: nec765.h,v 1.2 1993/10/16 13:48:50 rgrimes Exp $
+ * $Id: nec765.h,v 1.3 1994/09/17 16:56:10 davidg Exp $
*/
/*
@@ -121,6 +121,11 @@
#define NE7CMD_SCNLE 0xf9 /* scan less or equal */
#define NE7CMD_SCNGE 0xfd /* scan greater or equal */
+/*
+ * Enhanced controller commands:
+ */
+#define NE7CMD_VERSION 0x10 /* version (ok for all controllers) */
+
/*
* "specify" definitions
diff --git a/sys/i386/isa/fd.c b/sys/i386/isa/fd.c
index 241cf3b4af9b..e9c50002d600 100644
--- a/sys/i386/isa/fd.c
+++ b/sys/i386/isa/fd.c
@@ -5,11 +5,12 @@
* This code is derived from software contributed to Berkeley by
* Don Ahn.
*
- * Portions Copyright (c) 1993, 1994 by
+ * Portions Copyright (c) 1993, 1994, 1995 by
* jc@irbs.UUCP (John Capo)
* vak@zebub.msk.su (Serge Vakulenko)
* ache@astral.msk.su (Andrew A. Chernov)
* joerg_wunsch@uriah.sax.de (Joerg Wunsch)
+ * dufault@hda.com (Peter Dufault)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -40,7 +41,7 @@
* SUCH DAMAGE.
*
* from: @(#)fd.c 7.4 (Berkeley) 5/25/91
- * $Id: fd.c,v 1.45 1994/11/30 12:04:28 jkh Exp $
+ * $Id: fd.c,v 1.46 1994/12/04 20:22:19 joerg Exp $
*
*/
@@ -76,6 +77,7 @@
#include <i386/isa/fdreg.h>
#include <i386/isa/fdc.h>
#include <i386/isa/rtc.h>
+#include <machine/stdarg.h>
#if NFT > 0
#include <sys/ftape.h>
#include <i386/isa/ftreg.h>
@@ -164,6 +166,11 @@ fd_goaway(struct kern_devconf *kdc, int force)
*/
#define id_physid id_scsiid
+/* error returns for fd_cmd() */
+#define FD_FAILED -1
+#define FD_NOT_VALID -2
+#define FDC_ERRMAX 100 /* do not log more */
+
#define NUMTYPES 14
#define NUMDENS (NUMTYPES - 6)
@@ -228,6 +235,7 @@ struct fd_data {
#define FD_MOTOR_WAIT 0x08 /* motor coming up */
int skip;
int hddrv;
+#define FD_NO_TRACK -2
int track; /* where we think the head is */
int options; /* user configurable options, see ioctl_fd.h */
int dkunit; /* disk stats unit number */
@@ -341,6 +349,136 @@ fdc_externalize(struct proc *p, struct kern_devconf *kdc, void *userp, size_t le
return isa_externalize(fdcdevs[kdc->kdc_unit], userp, &len);
}
+static int
+fdc_err(fdcu_t fdcu, const char *s)
+{
+ fdc_data[fdcu].fdc_errs++;
+ if(fdc_data[fdcu].fdc_errs < FDC_ERRMAX)
+ printf("fdc%d: %s: ", fdcu, s);
+ else if(fdc_data[fdcu].fdc_errs == FDC_ERRMAX)
+ printf("fdc%d: too many errors, not logging any more\n",
+ fdcu);
+
+ return FD_FAILED;
+}
+
+/*
+ * fd_cmd: Send a command to the chip. Takes a varargs with this structure:
+ * Unit number,
+ * # of output bytes, output bytes as ints ...,
+ * # of input bytes, input bytes as ints ...
+ */
+
+int
+fd_cmd(fdcu_t fdcu, int n_out, ...)
+{
+ u_char cmd;
+ int n_in;
+ int n;
+ va_list ap;
+
+ va_start(ap, n_out);
+ cmd = (u_char)(va_arg(ap, int));
+ va_end(ap);
+ va_start(ap, n_out);
+ for (n = 0; n < n_out; n++)
+ {
+ if (out_fdc(fdcu, va_arg(ap, int)) < 0)
+ {
+ char msg[50];
+ sprintf(msg,
+ "cmd %x failed at out byte %d of %d\n",
+ cmd, n + 1, n_out);
+ return fdc_err(fdcu, msg);
+ }
+ }
+ n_in = va_arg(ap, int);
+ for (n = 0; n < n_in; n++)
+ {
+ int *ptr = va_arg(ap, int *);
+ if (fd_in(fdcu, ptr) < 0)
+ {
+ char msg[50];
+ sprintf(msg,
+ "cmd %02x failed at in byte %d of %d\n",
+ cmd, n + 1, n_in);
+ return fdc_err(fdcu, msg);
+ }
+ }
+
+ return 0;
+}
+
+int
+fd_sense_drive_status(fdc_p fdc, int *st3p)
+{
+ int st3;
+
+ if (fd_cmd(fdc->fdcu, 2, NE7CMD_SENSED, fdc->fdu, 1, &st3))
+ {
+ return fdc_err(fdc->fdcu, "Sense Drive Status failed.\n");
+ }
+ if (st3p)
+ *st3p = st3;
+
+ return 0;
+}
+
+int
+fd_sense_int(fdc_p fdc, int *st0p, int *cylp)
+{
+ int st0, cyl;
+
+ int ret = fd_cmd(fdc->fdcu, 1, NE7CMD_SENSEI, 1, &st0);
+
+ if (ret)
+ {
+ (void)fdc_err(fdc->fdcu,
+ "sense intr err reading stat reg 0\n");
+ return ret;
+ }
+
+ if (st0p)
+ *st0p = st0;
+
+ if ((st0 & NE7_ST0_IC) == NE7_ST0_IC_IV)
+ {
+ /*
+ * There doesn't seem to have been an interrupt.
+ */
+ return FD_NOT_VALID;
+ }
+
+ if (fd_in(fdc->fdcu, &cyl) < 0)
+ {
+ return fdc_err(fdc->fdcu, "can't get cyl num\n");
+ }
+
+ if (cylp)
+ *cylp = cyl;
+
+ return 0;
+}
+
+
+int
+fd_read_status(fdc_p fdc, int fdsu)
+{
+ int i, ret;
+ for (i = 0; i < 7; i++)
+ {
+ if ((ret = fd_in(fdc->fdcu, fdc->status + i)))
+ break;
+ }
+
+ if (ret == 0)
+ fdc->flags |= FDC_STAT_VALID;
+ else
+ fdc->flags &= ~FDC_STAT_VALID;
+
+ return ret;
+}
+
/****************************************************************************/
/* autoconfiguration stuff */
/****************************************************************************/
@@ -348,12 +486,12 @@ struct isa_driver fdcdriver = {
fdprobe, fdattach, "fdc",
};
+
/*
* probe for existance of controller
*/
static int
-fdprobe(dev)
- struct isa_device *dev;
+fdprobe(struct isa_device *dev)
{
fdcu_t fdcu = dev->id_unit;
if(fdc_data[fdcu].flags & FDC_ATTACHED)
@@ -371,12 +509,12 @@ fdprobe(dev)
outb(dev->id_iobase+FDOUT, FDO_FRST);
/* see if it can handle a command */
- if (out_fdc(fdcu, NE7CMD_SPECIFY) < 0)
+ if (fd_cmd(fdcu,
+ 3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
+ 0))
{
return(0);
}
- out_fdc(fdcu, NE7_SPEC_1(3, 240));
- out_fdc(fdcu, NE7_SPEC_2(2, 0));
return (IO_FDCSIZE);
}
@@ -384,16 +522,16 @@ fdprobe(dev)
* wire controller into system, look for floppy units
*/
static int
-fdattach(dev)
- struct isa_device *dev;
+fdattach(struct isa_device *dev)
{
unsigned fdt;
fdu_t fdu;
fdcu_t fdcu = dev->id_unit;
fdc_p fdc = fdc_data + fdcu;
fd_p fd;
- int fdsu, st0, i;
+ int fdsu, st0, st3, i;
struct isa_device *fdup;
+ int ic_type = 0;
fdc_registerdev(dev);
@@ -403,7 +541,7 @@ fdattach(dev)
fdc->state = DEVIDLE;
/* reset controller, turn motor off, clear fdout mirror reg */
outb(fdc->baseport + FDOUT, ((fdc->fdout = 0)));
- printf("fdc%d:", fdcu);
+ printf("fdc%d: ", fdcu);
/* check for each floppy drive */
for (fdup = isa_biotab_fdc; fdup->id_driver != 0; fdup++) {
@@ -414,7 +552,7 @@ fdattach(dev)
if (fdu >= (NFD+NFT))
continue;
fdsu = fdup->id_physid;
- /* look up what bios thinks we have */
+ /* look up what bios thinks we have */
switch (fdu) {
case 0: fdt = (rtcin(RTC_FDISKETTE) & 0xf0);
break;
@@ -445,18 +583,51 @@ fdattach(dev)
/* select it */
set_motor(fdcu, fdsu, TURNON);
DELAY(1000000); /* 1 sec */
- out_fdc(fdcu, NE7CMD_SENSED);
- out_fdc(fdcu, fdsu);
- if(in_fdc(fdcu) & NE7_ST3_T0) {
+
+ if (ic_type == 0 &&
+ fd_cmd(fdcu, 1, NE7CMD_VERSION, 1, &ic_type) == 0)
+ {
+ ic_type = (u_char)ic_type;
+ switch( ic_type ) {
+ case 0x80:
+ printf("(NEC 765)");
+ fdc->fdct = FDC_NE765;
+ break;
+ case 0x81:
+ printf("(Intel 82077)");
+ fdc->fdct = FDC_I82077;
+ break;
+ case 0x90:
+ printf("(NEC 72065B)");
+ fdc->fdct = FDC_NE72065;
+ break;
+ default:
+ printf("(unknown IC type %02x)", ic_type);
+ fdc->fdct = FDC_UNKNOWN;
+ break;
+ }
+ }
+ if ((fd_cmd(fdcu, 2, NE7CMD_SENSED, fdsu, 1, &st3) == 0) &&
+ (st3 & NE7_ST3_T0)) {
/* if at track 0, first seek inwards */
- out_fdc(fdcu, NE7CMD_SEEK); /* seek some steps... */
- out_fdc(fdcu, fdsu);
- out_fdc(fdcu, 10);
+ /* seek some steps: */
+ (void)fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0);
DELAY(300000); /* ...wait a moment... */
- out_fdc(fdcu, NE7CMD_SENSEI); /* make ctrlr happy */
- (void)in_fdc(fdcu);
- (void)in_fdc(fdcu);
+ (void)fd_sense_int(fdc, 0, 0); /* make ctrlr happy */
+ }
+
+ /* If we're at track 0 first seek inwards. */
+ if ((fd_sense_drive_status(fdc, &st3) == 0) &&
+ (st3 & NE7_ST3_T0)) {
+ /* Seek some steps... */
+ if (fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) {
+ /* ...wait a moment... */
+ DELAY(300000);
+ /* make ctrlr happy: */
+ (void)fd_sense_int(fdc, 0, 0);
+ }
}
+
for(i = 0; i < 2; i++) {
/*
* we must recalibrate twice, just in case the
@@ -464,18 +635,16 @@ fdattach(dev)
* FDCs still barf when attempting to recalibrate
* more than 77 steps
*/
- out_fdc(fdcu, NE7CMD_RECAL); /* go back to 0 */
- out_fdc(fdcu, fdsu);
- /* a second being enough for full stroke seek */
- DELAY(i == 0? 1000000: 300000);
+ /* go back to 0: */
+ if (fd_cmd(fdcu, 2, NE7CMD_RECAL, fdsu, 0) == 0) {
+ /* a second being enough for full stroke seek*/
+ DELAY(i == 0? 1000000: 300000);
- /* anything responding? */
- out_fdc(fdcu, NE7CMD_SENSEI);
- st0 = in_fdc(fdcu);
- (void)in_fdc(fdcu);
-
- if ((st0 & NE7_ST0_EC) == 0)
- break; /* already probed succesfully */
+ /* anything responding? */
+ if (fd_sense_int(fdc, &st0, 0) == 0 &&
+ (st0 & NE7_ST0_EC) == 0)
+ break; /* already probed succesfully */
+ }
}
set_motor(fdcu, fdsu, TURNOFF);
@@ -483,7 +652,7 @@ fdattach(dev)
if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */
continue;
- fd->track = -2;
+ fd->track = FD_NO_TRACK;
fd->fdc = fdc;
fd->fdsu = fdsu;
fd->options = 0;
@@ -530,8 +699,7 @@ fdattach(dev)
}
int
-fdsize(dev)
- dev_t dev;
+fdsize(dev_t dev)
{
return(0);
}
@@ -541,10 +709,7 @@ fdsize(dev)
/* remember to not deselect the drive we're working on */
/****************************************************************************/
static void
-set_motor(fdcu, fdsu, turnon)
- fdcu_t fdcu;
- int fdsu;
- int turnon;
+set_motor(fdcu_t fdcu, int fdsu, int turnon)
{
int fdout = fdc_data[fdcu].fdout;
int needspecify = 0;
@@ -572,13 +737,14 @@ set_motor(fdcu, fdsu, turnon)
if(needspecify) {
/*
+ * XXX
* special case: since we have just woken up the FDC
* from its sleep, we silently assume the command will
* be accepted, and do not test for a timeout
*/
- out_fdc(fdcu, NE7CMD_SPECIFY);
- out_fdc(fdcu, NE7_SPEC_1(3, 240));
- out_fdc(fdcu, NE7_SPEC_2(2, 0));
+ (void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY,
+ NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
+ 0);
}
}
@@ -614,8 +780,7 @@ fd_motor_on(void *arg1)
}
static void
-fd_turnon(fdu)
- fdu_t fdu;
+fd_turnon(fdu_t fdu)
{
fd_p fd = fd_data + fdu;
if(!(fd->flags & FD_MOTOR))
@@ -627,8 +792,7 @@ fd_turnon(fdu)
}
static void
-fdc_reset(fdc)
- fdc_p fdc;
+fdc_reset(fdc_p fdc)
{
fdcu_t fdcu = fdc->fdcu;
@@ -643,26 +807,26 @@ fdc_reset(fdc)
outb(fdc->baseport + FDOUT, fdc->fdout);
TRACE1("[0x%x->FDOUT]", fdc->fdout);
- /* after a reset, silently believe the FDC will accept commands */
- out_fdc(fdcu, NE7CMD_SPECIFY);
- out_fdc(fdcu, NE7_SPEC_1(3, 240));
- out_fdc(fdcu, NE7_SPEC_2(2, 0));
+ /* XXX after a reset, silently believe the FDC will accept commands */
+ (void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY,
+ NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
+ 0);
}
/****************************************************************************/
/* fdc in/out */
/****************************************************************************/
int
-in_fdc(fdcu)
- fdcu_t fdcu;
+in_fdc(fdcu_t fdcu)
{
int baseport = fdc_data[fdcu].baseport;
int i, j = 100000;
while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM))
!= (NE7_DIO|NE7_RQM) && j-- > 0)
- if (i == NE7_RQM) return -1;
+ if (i == NE7_RQM)
+ return fdc_err(fdcu, "ready for output in input");
if (j <= 0)
- return(-1);
+ return fdc_err(fdcu, "input ready timeout");
#ifdef DEBUG
i = inb(baseport+FDDATA);
TRACE1("[FDDATA->0x%x]", (unsigned char)i);
@@ -672,10 +836,35 @@ in_fdc(fdcu)
#endif
}
+/*
+ * fd_in: Like in_fdc, but allows you to see if it worked.
+ */
int
-out_fdc(fdcu, x)
- fdcu_t fdcu;
- int x;
+fd_in(fdcu_t fdcu, int *ptr)
+{
+ int baseport = fdc_data[fdcu].baseport;
+ int i, j = 100000;
+ while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM))
+ != (NE7_DIO|NE7_RQM) && j-- > 0)
+ if (i == NE7_RQM)
+ return fdc_err(fdcu, "ready for output in input");
+ if (j <= 0)
+ return fdc_err(fdcu, "input ready timeout");
+#ifdef DEBUG
+ i = inb(baseport+FDDATA);
+ TRACE1("[FDDATA->0x%x]", (unsigned char)i);
+ *ptr = i;
+ return 0;
+#else
+ i = inb(baseport+FDDATA);
+ if (ptr)
+ *ptr = i;
+ return 0;
+#endif
+}
+
+int
+out_fdc(fdcu_t fdcu, int x)
{
int baseport = fdc_data[fdcu].baseport;
int i;
@@ -683,12 +872,12 @@ out_fdc(fdcu, x)
/* Check that the direction bit is set */
i = 100000;
while ((inb(baseport+FDSTS) & NE7_DIO) && i-- > 0);
- if (i <= 0) return (-1); /* Floppy timed out */
+ if (i <= 0) return fdc_err(fdcu, "direction bit not set");
/* Check that the floppy controller is ready for a command */
i = 100000;
while ((inb(baseport+FDSTS) & NE7_RQM) == 0 && i-- > 0);
- if (i <= 0) return (-1); /* Floppy timed out */
+ if (i <= 0) return fdc_err(fdcu, "output ready timeout");
/* Send the command and return */
outb(baseport+FDDATA, x);
@@ -700,9 +889,7 @@ out_fdc(fdcu, x)
/* fdopen/fdclose */
/****************************************************************************/
int
-Fdopen(dev, flags)
- dev_t dev;
- int flags;
+Fdopen(dev_t dev, int flags)
{
fdu_t fdu = FDUNIT(minor(dev));
int type = FDTYPE(minor(dev));
@@ -777,16 +964,23 @@ Fdopen(dev, flags)
set_motor(fdc->fdcu, fd_data[fdu].fdsu, TURNON);
if (flags & FWRITE) {
- /* Check to make sure the diskette */
- /* is writable */
- out_fdc(fdc->fdcu, NE7CMD_SENSED);
- out_fdc(fdc->fdcu, fdu);
- st3 = in_fdc(fdc->fdcu);
- if(st3 & NE7_ST3_WP) {
- printf("fd%d: write protected\n", fdu);
- set_motor(fdc->fdcu, fd_data[fdu].fdsu, TURNOFF);
- return(EPERM);
+ /*
+ * Check to make sure the diskette is writable:
+ */
+ int err = 0;
+
+ if (fd_sense_drive_status(fdc, &st3) != 0)
+ err = EIO;
+ else if ( (st3 & NE7_ST3_WP) )
+ {
+ printf("fd%d: drive is write protected.\n", fdu);
+ err = ENXIO;
}
+
+ if (err) {
+ set_motor(fdc->fdcu, fd_data[fdu].fdsu, TURNOFF);
+ return err;
+ }
}
set_motor(fdc->fdcu, fd_data[fdu].fdsu, TURNOFF);
@@ -798,9 +992,7 @@ Fdopen(dev, flags)
}
int
-fdclose(dev, flags)
- dev_t dev;
- int flags;
+fdclose(dev_t dev, int flags)
{
fdu_t fdu = FDUNIT(minor(dev));
@@ -853,7 +1045,8 @@ fdstrategy(struct buf *bp)
#endif
if (!(bp->b_flags & B_FORMAT)) {
if ((fdu >= NFD) || (bp->b_blkno < 0)) {
- printf("fdstrat: fdu = %d, blkno = %lu, bcount = %ld\n",
+ printf(
+ "fdstrat: fd%d: bad request blkno = %lu, bcount = %ld\n",
fdu, (u_long)bp->b_blkno, bp->b_bcount);
bp->b_error = EINVAL;
bp->b_flags |= B_ERROR;
@@ -903,8 +1096,7 @@ bad:
* will pick up our work when the present work completes *
\***************************************************************/
static void
-fdstart(fdcu)
- fdcu_t fdcu;
+fdstart(fdcu_t fdcu)
{
int s;
@@ -1005,9 +1197,7 @@ fdintr(fdcu_t fdcu)
* if it returns a non zero value, it should be called again immediatly *
\***********************************************************************/
static int
-fdstate(fdcu, fdc)
- fdcu_t fdcu;
- fdc_p fdc;
+fdstate(fdcu_t fdcu, fdc_p fdc)
{
int read, format, head, sec = 0, i = 0, sectrac, st0, cyl, st3;
unsigned long blknum;
@@ -1092,7 +1282,9 @@ fdstate(fdcu, fdc)
fdc->state = SEEKCOMPLETE;
break;
}
- if(out_fdc(fdcu, NE7CMD_SEEK) < 0) /* Seek function */
+ if (fd_cmd(fdcu, 3, NE7CMD_SEEK,
+ fd->fdsu, bp->b_cylin * fd->ft->steptrac,
+ 0))
{
/*
* seek command not accepted, looks like
@@ -1101,9 +1293,7 @@ fdstate(fdcu, fdc)
fdc->retry = 6; /* try a reset */
return(retrier(fdcu));
}
- out_fdc(fdcu, fd->fdsu); /* Drive number */
- out_fdc(fdcu, bp->b_cylin * fd->ft->steptrac);
- fd->track = -2;
+ fd->track = FD_NO_TRACK;
fdc->state = SEEKWAIT;
return(0); /* will return later */
case SEEKWAIT:
@@ -1113,37 +1303,63 @@ fdstate(fdcu, fdc)
return(0); /* will return later */
case SEEKCOMPLETE : /* SEEK DONE, START DMA */
/* Make sure seek really happened*/
- if(fd->track == -2)
+ if(fd->track == FD_NO_TRACK)
{
int descyl = bp->b_cylin * fd->ft->steptrac;
do {
- out_fdc(fdcu, NE7CMD_SENSEI);
- st0 = in_fdc(fdcu);
- cyl = in_fdc(fdcu);
/*
- * if this was a "ready changed" interrupt,
- * fetch status again (can happen after
- * enabling controller from reset state)
+ * This might be a "ready changed" interrupt,
+ * which cannot really happen since the
+ * RDY pin is hardwired to + 5 volts. This
+ * generally indicates a "bouncing" intr
+ * line, so do one of the following:
+ *
+ * When running on an enhanced FDC that is
+ * known to not go stuck after responding
+ * with INVALID, fetch all interrupt states
+ * until seeing either an INVALID or a
+ * real interrupt condition.
+ *
+ * When running on a dumb old NE765, give
+ * up immediately. The controller will
+ * provide up to four dummy RC interrupt
+ * conditions right after reset (for the
+ * corresponding four drives), so this is
+ * our only chance to get notice that it
+ * was not the FDC that caused the interrupt.
*/
+ if (fd_sense_int(fdc, &st0, &cyl)
+ == FD_NOT_VALID)
+ return 0;
+ if(fdc->fdct == FDC_NE765
+ && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC)
+ return 0; /* hope for a real intr */
} while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
+
if (0 == descyl)
{
+ int failed = 0;
/*
* seek to cyl 0 requested; make sure we are
* really there
*/
- out_fdc(fdcu, NE7CMD_SENSED);
- out_fdc(fdcu, fdu);
- st3 = in_fdc(fdcu);
+ if (fd_sense_drive_status(fdc, &st3))
+ failed = 1;
if ((st3 & NE7_ST3_T0) == 0) {
printf(
"fd%d: Seek to cyl 0, but not really there (ST3 = %b)\n",
fdu, st3, NE7_ST3BITS);
+ failed = 1;
+ }
+
+ if (failed)
+ {
if(fdc->retry < 3)
fdc->retry = 3;
return(retrier(fdcu));
}
}
+
if (cyl != descyl)
{
printf(
@@ -1170,14 +1386,12 @@ fdstate(fdcu, fdc)
if(format || !read)
{
/* make sure the drive is writable */
- if(out_fdc(fdcu, NE7CMD_SENSED) < 0)
+ if(fd_sense_drive_status(fdc, &st3) != 0)
{
/* stuck controller? */
fdc->retry = 6; /* reset the beast */
return(retrier(fdcu));
}
- out_fdc(fdcu, fdu);
- st3 = in_fdc(fdcu);
if(st3 & NE7_ST3_WP)
{
/*
@@ -1202,48 +1416,56 @@ fdstate(fdcu, fdc)
if(format)
{
/* formatting */
- if(out_fdc(fdcu, NE7CMD_FORMAT) < 0)
+ if(fd_cmd(fdcu, 6,
+ NE7CMD_FORMAT,
+ head << 2 | fdu,
+ finfo->fd_formb_secshift,
+ finfo->fd_formb_nsecs,
+ finfo->fd_formb_gaplen,
+ finfo->fd_formb_fillbyte,
+ 0))
{
/* controller fell over */
fdc->retry = 6;
return(retrier(fdcu));
}
- out_fdc(fdcu, head << 2 | fdu);
- out_fdc(fdcu, finfo->fd_formb_secshift);
- out_fdc(fdcu, finfo->fd_formb_nsecs);
- out_fdc(fdcu, finfo->fd_formb_gaplen);
- out_fdc(fdcu, finfo->fd_formb_fillbyte);
}
else
{
- if ((read && out_fdc(fdcu, NE7CMD_READ) < 0)
- || (!read /* i.e., write */
- && out_fdc(fdcu, NE7CMD_WRITE) < 0))
+ if (fd_cmd(fdcu, 9,
+ (read ? NE7CMD_READ : NE7CMD_WRITE),
+ head << 2 | fdu, /* head & unit */
+ fd->track, /* track */
+ head,
+ sec, /* sector + 1 */
+ fd->ft->secsize, /* sector size */
+ sectrac, /* sectors/track */
+ fd->ft->gap, /* gap size */
+ fd->ft->datalen, /* data length */
+ 0))
{
/* the beast is sleeping again */
fdc->retry = 6;
return(retrier(fdcu));
}
- out_fdc(fdcu, head << 2 | fdu); /* head & unit */
- out_fdc(fdcu, fd->track); /* track */
- out_fdc(fdcu, head);
- out_fdc(fdcu, sec); /* sector XXX +1? */
- out_fdc(fdcu, fd->ft->secsize); /* sector size */
- out_fdc(fdcu, sectrac); /* sectors/track */
- out_fdc(fdcu, fd->ft->gap); /* gap size */
- out_fdc(fdcu, fd->ft->datalen); /* data length */
}
fdc->state = IOCOMPLETE;
timeout(fd_timeout, (caddr_t)fdcu, hz);
return(0); /* will return later */
case IOCOMPLETE: /* IO DONE, post-analyze */
untimeout(fd_timeout, (caddr_t)fdcu);
- for(i=0;i<7;i++)
+
+ if (fd_read_status(fdc, fd->fdsu))
{
- fdc->status[i] = in_fdc(fdcu);
- }
+ if (fdc->retry < 6)
+ fdc->retry = 6; /* force a reset */
+ return retrier(fdcu);
+ }
+
fdc->state = IOTIMEDOUT;
+
/* FALLTHROUGH */
+
case IOTIMEDOUT:
isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip,
format ? bp->b_bcount : fdblk, fdc->dmachan);
@@ -1299,13 +1521,14 @@ fdstate(fdcu, fdc)
fdc->state = STARTRECAL;
break;
case STARTRECAL:
- if(out_fdc(fdcu, NE7CMD_RECAL) < 0) /* Recalibrate Function */
+ if(fd_cmd(fdcu,
+ 2, NE7CMD_RECAL, fdu,
+ 0)) /* Recalibrate Function */
{
/* arrgl */
fdc->retry = 6;
return(retrier(fdcu));
}
- out_fdc(fdcu, fdu);
fdc->state = RECALWAIT;
return(0); /* will return later */
case RECALWAIT:
@@ -1315,14 +1538,14 @@ fdstate(fdcu, fdc)
return(0); /* will return later */
case RECALCOMPLETE:
do {
- out_fdc(fdcu, NE7CMD_SENSEI);
- st0 = in_fdc(fdcu);
- cyl = in_fdc(fdcu);
/*
- * if this was a "ready changed" interrupt,
- * fetch status again (can happen after
- * enabling controller from reset state)
+ * See SEEKCOMPLETE for a comment on this:
*/
+ if (fd_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID)
+ return 0;
+ if(fdc->fdct == FDC_NE765
+ && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC)
+ return 0; /* hope for a real intr */
} while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
if ((st0 & NE7_ST0_IC) != NE7_ST0_IC_NT || cyl != 0)
{
@@ -1357,22 +1580,15 @@ fdstate(fdcu, fdc)
fdc->state = STARTRECAL;
return(1); /* will return immediatly */
default:
- printf("Unexpected FD int->");
- if(out_fdc(fdcu, NE7CMD_SENSEI) < 0)
+ printf("fdc%d: Unexpected FD int->", fdcu);
+ if (fd_sense_int(fdc, &st0, &cyl) != 0)
{
printf("[controller is dead now]\n");
return(0);
}
- st0 = in_fdc(fdcu);
- cyl = in_fdc(fdcu);
printf("ST0 = %x, PCN = %x\n", st0, cyl);
- out_fdc(fdcu, NE7CMD_READID);
- out_fdc(fdcu, fd->fdsu);
- for(i=0;i<7;i++) {
- fdc->status[i] = in_fdc(fdcu);
- }
- if(fdc->status[0] != -1)
- printf("intr status :%lx %lx %lx %lx %lx %lx %lx\n",
+ if (fd_read_status(fdc, fd->fdsu) == 0)
+ printf("FDC status :%lx %lx %lx %lx %lx %lx %lx\n",
fdc->status[0],
fdc->status[1],
fdc->status[2],
@@ -1381,7 +1597,7 @@ fdstate(fdcu, fdc)
fdc->status[5],
fdc->status[6] );
else
- printf("FDC timed out\n");
+ printf("No status available\n");
return(0);
}
return(1); /* Come back immediatly to new state */
@@ -1423,11 +1639,18 @@ retrier(fdcu)
fdc->fd->skip / DEV_BSIZE,
(struct disklabel *)NULL);
bp->b_dev = sav_b_dev;
- printf(" (ST0 %b ", fdc->status[0], NE7_ST0BITS);
- printf(" ST1 %b ", fdc->status[1], NE7_ST1BITS);
- printf(" ST2 %b ", fdc->status[2], NE7_ST2BITS);
- printf("cyl %ld hd %ld sec %ld)\n",
- fdc->status[3], fdc->status[4], fdc->status[5]);
+ if (fdc->flags & FDC_STAT_VALID)
+ {
+ printf(
+ " (ST0 %b ST1 %b ST2 %b cyl %ld hd %ld sec %ld)\n",
+ fdc->status[0], NE7_ST0BITS,
+ fdc->status[1], NE7_ST1BITS,
+ fdc->status[2], NE7_ST2BITS,
+ fdc->status[3], fdc->status[4],
+ fdc->status[5]);
+ }
+ else
+ printf(" (No status)\n");
}
bp->b_flags |= B_ERROR;
bp->b_error = EIO;
diff --git a/sys/i386/isa/fdc.h b/sys/i386/isa/fdc.h
index 950ef2346e9f..0216b7aa2e2e 100644
--- a/sys/i386/isa/fdc.h
+++ b/sys/i386/isa/fdc.h
@@ -31,10 +31,15 @@
* SUCH DAMAGE.
*
* from: @(#)fd.c 7.4 (Berkeley) 5/25/91
- * $Id: fdc.h,v 1.3 1994/09/17 16:56:07 davidg Exp $
+ * $Id: fdc.h,v 1.4 1994/10/10 01:12:26 phk Exp $
*
*/
+enum fdc_type
+{
+ FDC_NE765, FDC_I82077, FDC_NE72065, FDC_UNKNOWN = -1
+};
+
/***********************************************************************\
* Per controller structure. *
@@ -48,13 +53,16 @@ struct fdc_data
#define FDC_ATTACHED 0x01
#define FDC_HASFTAPE 0x02
#define FDC_TAPE_BUSY 0x04
+#define FDC_STAT_VALID 0x08
struct fd_data *fd;
int fdu; /* the active drive */
int state;
int retry;
int fdout; /* mirror of the w/o digital output reg */
u_long status[7]; /* copy of the registers */
- struct buf head; /* Head of buf chain */
+ enum fdc_type fdct; /* chip version of FDC */
+ int fdc_errs; /* number of logged errors */
+ struct buf head; /* Head of buf chain */
};
/***********************************************************************\
@@ -70,6 +78,7 @@ typedef int fdcu_t;
typedef int fdsu_t;
typedef struct fd_data *fd_p;
typedef struct fdc_data *fdc_p;
+typedef enum fdc_type fdc_t;
-#define FDUNIT(s) (((s)>>6)&03)
-#define FDTYPE(s) ((s)&077)
+#define FDUNIT(s) (((s)>>6)&03)
+#define FDTYPE(s) ((s)&077)
diff --git a/sys/i386/isa/ic/nec765.h b/sys/i386/isa/ic/nec765.h
index 9f93b705efe4..810e825bd66e 100644
--- a/sys/i386/isa/ic/nec765.h
+++ b/sys/i386/isa/ic/nec765.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)nec765.h 7.1 (Berkeley) 5/9/91
- * $Id: nec765.h,v 1.2 1993/10/16 13:48:50 rgrimes Exp $
+ * $Id: nec765.h,v 1.3 1994/09/17 16:56:10 davidg Exp $
*/
/*
@@ -121,6 +121,11 @@
#define NE7CMD_SCNLE 0xf9 /* scan less or equal */
#define NE7CMD_SCNGE 0xfd /* scan greater or equal */
+/*
+ * Enhanced controller commands:
+ */
+#define NE7CMD_VERSION 0x10 /* version (ok for all controllers) */
+
/*
* "specify" definitions
diff --git a/sys/isa/fd.c b/sys/isa/fd.c
index 241cf3b4af9b..e9c50002d600 100644
--- a/sys/isa/fd.c
+++ b/sys/isa/fd.c
@@ -5,11 +5,12 @@
* This code is derived from software contributed to Berkeley by
* Don Ahn.
*
- * Portions Copyright (c) 1993, 1994 by
+ * Portions Copyright (c) 1993, 1994, 1995 by
* jc@irbs.UUCP (John Capo)
* vak@zebub.msk.su (Serge Vakulenko)
* ache@astral.msk.su (Andrew A. Chernov)
* joerg_wunsch@uriah.sax.de (Joerg Wunsch)
+ * dufault@hda.com (Peter Dufault)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -40,7 +41,7 @@
* SUCH DAMAGE.
*
* from: @(#)fd.c 7.4 (Berkeley) 5/25/91
- * $Id: fd.c,v 1.45 1994/11/30 12:04:28 jkh Exp $
+ * $Id: fd.c,v 1.46 1994/12/04 20:22:19 joerg Exp $
*
*/
@@ -76,6 +77,7 @@
#include <i386/isa/fdreg.h>
#include <i386/isa/fdc.h>
#include <i386/isa/rtc.h>
+#include <machine/stdarg.h>
#if NFT > 0
#include <sys/ftape.h>
#include <i386/isa/ftreg.h>
@@ -164,6 +166,11 @@ fd_goaway(struct kern_devconf *kdc, int force)
*/
#define id_physid id_scsiid
+/* error returns for fd_cmd() */
+#define FD_FAILED -1
+#define FD_NOT_VALID -2
+#define FDC_ERRMAX 100 /* do not log more */
+
#define NUMTYPES 14
#define NUMDENS (NUMTYPES - 6)
@@ -228,6 +235,7 @@ struct fd_data {
#define FD_MOTOR_WAIT 0x08 /* motor coming up */
int skip;
int hddrv;
+#define FD_NO_TRACK -2
int track; /* where we think the head is */
int options; /* user configurable options, see ioctl_fd.h */
int dkunit; /* disk stats unit number */
@@ -341,6 +349,136 @@ fdc_externalize(struct proc *p, struct kern_devconf *kdc, void *userp, size_t le
return isa_externalize(fdcdevs[kdc->kdc_unit], userp, &len);
}
+static int
+fdc_err(fdcu_t fdcu, const char *s)
+{
+ fdc_data[fdcu].fdc_errs++;
+ if(fdc_data[fdcu].fdc_errs < FDC_ERRMAX)
+ printf("fdc%d: %s: ", fdcu, s);
+ else if(fdc_data[fdcu].fdc_errs == FDC_ERRMAX)
+ printf("fdc%d: too many errors, not logging any more\n",
+ fdcu);
+
+ return FD_FAILED;
+}
+
+/*
+ * fd_cmd: Send a command to the chip. Takes a varargs with this structure:
+ * Unit number,
+ * # of output bytes, output bytes as ints ...,
+ * # of input bytes, input bytes as ints ...
+ */
+
+int
+fd_cmd(fdcu_t fdcu, int n_out, ...)
+{
+ u_char cmd;
+ int n_in;
+ int n;
+ va_list ap;
+
+ va_start(ap, n_out);
+ cmd = (u_char)(va_arg(ap, int));
+ va_end(ap);
+ va_start(ap, n_out);
+ for (n = 0; n < n_out; n++)
+ {
+ if (out_fdc(fdcu, va_arg(ap, int)) < 0)
+ {
+ char msg[50];
+ sprintf(msg,
+ "cmd %x failed at out byte %d of %d\n",
+ cmd, n + 1, n_out);
+ return fdc_err(fdcu, msg);
+ }
+ }
+ n_in = va_arg(ap, int);
+ for (n = 0; n < n_in; n++)
+ {
+ int *ptr = va_arg(ap, int *);
+ if (fd_in(fdcu, ptr) < 0)
+ {
+ char msg[50];
+ sprintf(msg,
+ "cmd %02x failed at in byte %d of %d\n",
+ cmd, n + 1, n_in);
+ return fdc_err(fdcu, msg);
+ }
+ }
+
+ return 0;
+}
+
+int
+fd_sense_drive_status(fdc_p fdc, int *st3p)
+{
+ int st3;
+
+ if (fd_cmd(fdc->fdcu, 2, NE7CMD_SENSED, fdc->fdu, 1, &st3))
+ {
+ return fdc_err(fdc->fdcu, "Sense Drive Status failed.\n");
+ }
+ if (st3p)
+ *st3p = st3;
+
+ return 0;
+}
+
+int
+fd_sense_int(fdc_p fdc, int *st0p, int *cylp)
+{
+ int st0, cyl;
+
+ int ret = fd_cmd(fdc->fdcu, 1, NE7CMD_SENSEI, 1, &st0);
+
+ if (ret)
+ {
+ (void)fdc_err(fdc->fdcu,
+ "sense intr err reading stat reg 0\n");
+ return ret;
+ }
+
+ if (st0p)
+ *st0p = st0;
+
+ if ((st0 & NE7_ST0_IC) == NE7_ST0_IC_IV)
+ {
+ /*
+ * There doesn't seem to have been an interrupt.
+ */
+ return FD_NOT_VALID;
+ }
+
+ if (fd_in(fdc->fdcu, &cyl) < 0)
+ {
+ return fdc_err(fdc->fdcu, "can't get cyl num\n");
+ }
+
+ if (cylp)
+ *cylp = cyl;
+
+ return 0;
+}
+
+
+int
+fd_read_status(fdc_p fdc, int fdsu)
+{
+ int i, ret;
+ for (i = 0; i < 7; i++)
+ {
+ if ((ret = fd_in(fdc->fdcu, fdc->status + i)))
+ break;
+ }
+
+ if (ret == 0)
+ fdc->flags |= FDC_STAT_VALID;
+ else
+ fdc->flags &= ~FDC_STAT_VALID;
+
+ return ret;
+}
+
/****************************************************************************/
/* autoconfiguration stuff */
/****************************************************************************/
@@ -348,12 +486,12 @@ struct isa_driver fdcdriver = {
fdprobe, fdattach, "fdc",
};
+
/*
* probe for existance of controller
*/
static int
-fdprobe(dev)
- struct isa_device *dev;
+fdprobe(struct isa_device *dev)
{
fdcu_t fdcu = dev->id_unit;
if(fdc_data[fdcu].flags & FDC_ATTACHED)
@@ -371,12 +509,12 @@ fdprobe(dev)
outb(dev->id_iobase+FDOUT, FDO_FRST);
/* see if it can handle a command */
- if (out_fdc(fdcu, NE7CMD_SPECIFY) < 0)
+ if (fd_cmd(fdcu,
+ 3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
+ 0))
{
return(0);
}
- out_fdc(fdcu, NE7_SPEC_1(3, 240));
- out_fdc(fdcu, NE7_SPEC_2(2, 0));
return (IO_FDCSIZE);
}
@@ -384,16 +522,16 @@ fdprobe(dev)
* wire controller into system, look for floppy units
*/
static int
-fdattach(dev)
- struct isa_device *dev;
+fdattach(struct isa_device *dev)
{
unsigned fdt;
fdu_t fdu;
fdcu_t fdcu = dev->id_unit;
fdc_p fdc = fdc_data + fdcu;
fd_p fd;
- int fdsu, st0, i;
+ int fdsu, st0, st3, i;
struct isa_device *fdup;
+ int ic_type = 0;
fdc_registerdev(dev);
@@ -403,7 +541,7 @@ fdattach(dev)
fdc->state = DEVIDLE;
/* reset controller, turn motor off, clear fdout mirror reg */
outb(fdc->baseport + FDOUT, ((fdc->fdout = 0)));
- printf("fdc%d:", fdcu);
+ printf("fdc%d: ", fdcu);
/* check for each floppy drive */
for (fdup = isa_biotab_fdc; fdup->id_driver != 0; fdup++) {
@@ -414,7 +552,7 @@ fdattach(dev)
if (fdu >= (NFD+NFT))
continue;
fdsu = fdup->id_physid;
- /* look up what bios thinks we have */
+ /* look up what bios thinks we have */
switch (fdu) {
case 0: fdt = (rtcin(RTC_FDISKETTE) & 0xf0);
break;
@@ -445,18 +583,51 @@ fdattach(dev)
/* select it */
set_motor(fdcu, fdsu, TURNON);
DELAY(1000000); /* 1 sec */
- out_fdc(fdcu, NE7CMD_SENSED);
- out_fdc(fdcu, fdsu);
- if(in_fdc(fdcu) & NE7_ST3_T0) {
+
+ if (ic_type == 0 &&
+ fd_cmd(fdcu, 1, NE7CMD_VERSION, 1, &ic_type) == 0)
+ {
+ ic_type = (u_char)ic_type;
+ switch( ic_type ) {
+ case 0x80:
+ printf("(NEC 765)");
+ fdc->fdct = FDC_NE765;
+ break;
+ case 0x81:
+ printf("(Intel 82077)");
+ fdc->fdct = FDC_I82077;
+ break;
+ case 0x90:
+ printf("(NEC 72065B)");
+ fdc->fdct = FDC_NE72065;
+ break;
+ default:
+ printf("(unknown IC type %02x)", ic_type);
+ fdc->fdct = FDC_UNKNOWN;
+ break;
+ }
+ }
+ if ((fd_cmd(fdcu, 2, NE7CMD_SENSED, fdsu, 1, &st3) == 0) &&
+ (st3 & NE7_ST3_T0)) {
/* if at track 0, first seek inwards */
- out_fdc(fdcu, NE7CMD_SEEK); /* seek some steps... */
- out_fdc(fdcu, fdsu);
- out_fdc(fdcu, 10);
+ /* seek some steps: */
+ (void)fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0);
DELAY(300000); /* ...wait a moment... */
- out_fdc(fdcu, NE7CMD_SENSEI); /* make ctrlr happy */
- (void)in_fdc(fdcu);
- (void)in_fdc(fdcu);
+ (void)fd_sense_int(fdc, 0, 0); /* make ctrlr happy */
+ }
+
+ /* If we're at track 0 first seek inwards. */
+ if ((fd_sense_drive_status(fdc, &st3) == 0) &&
+ (st3 & NE7_ST3_T0)) {
+ /* Seek some steps... */
+ if (fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) {
+ /* ...wait a moment... */
+ DELAY(300000);
+ /* make ctrlr happy: */
+ (void)fd_sense_int(fdc, 0, 0);
+ }
}
+
for(i = 0; i < 2; i++) {
/*
* we must recalibrate twice, just in case the
@@ -464,18 +635,16 @@ fdattach(dev)
* FDCs still barf when attempting to recalibrate
* more than 77 steps
*/
- out_fdc(fdcu, NE7CMD_RECAL); /* go back to 0 */
- out_fdc(fdcu, fdsu);
- /* a second being enough for full stroke seek */
- DELAY(i == 0? 1000000: 300000);
+ /* go back to 0: */
+ if (fd_cmd(fdcu, 2, NE7CMD_RECAL, fdsu, 0) == 0) {
+ /* a second being enough for full stroke seek*/
+ DELAY(i == 0? 1000000: 300000);
- /* anything responding? */
- out_fdc(fdcu, NE7CMD_SENSEI);
- st0 = in_fdc(fdcu);
- (void)in_fdc(fdcu);
-
- if ((st0 & NE7_ST0_EC) == 0)
- break; /* already probed succesfully */
+ /* anything responding? */
+ if (fd_sense_int(fdc, &st0, 0) == 0 &&
+ (st0 & NE7_ST0_EC) == 0)
+ break; /* already probed succesfully */
+ }
}
set_motor(fdcu, fdsu, TURNOFF);
@@ -483,7 +652,7 @@ fdattach(dev)
if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */
continue;
- fd->track = -2;
+ fd->track = FD_NO_TRACK;
fd->fdc = fdc;
fd->fdsu = fdsu;
fd->options = 0;
@@ -530,8 +699,7 @@ fdattach(dev)
}
int
-fdsize(dev)
- dev_t dev;
+fdsize(dev_t dev)
{
return(0);
}
@@ -541,10 +709,7 @@ fdsize(dev)
/* remember to not deselect the drive we're working on */
/****************************************************************************/
static void
-set_motor(fdcu, fdsu, turnon)
- fdcu_t fdcu;
- int fdsu;
- int turnon;
+set_motor(fdcu_t fdcu, int fdsu, int turnon)
{
int fdout = fdc_data[fdcu].fdout;
int needspecify = 0;
@@ -572,13 +737,14 @@ set_motor(fdcu, fdsu, turnon)
if(needspecify) {
/*
+ * XXX
* special case: since we have just woken up the FDC
* from its sleep, we silently assume the command will
* be accepted, and do not test for a timeout
*/
- out_fdc(fdcu, NE7CMD_SPECIFY);
- out_fdc(fdcu, NE7_SPEC_1(3, 240));
- out_fdc(fdcu, NE7_SPEC_2(2, 0));
+ (void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY,
+ NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
+ 0);
}
}
@@ -614,8 +780,7 @@ fd_motor_on(void *arg1)
}
static void
-fd_turnon(fdu)
- fdu_t fdu;
+fd_turnon(fdu_t fdu)
{
fd_p fd = fd_data + fdu;
if(!(fd->flags & FD_MOTOR))
@@ -627,8 +792,7 @@ fd_turnon(fdu)
}
static void
-fdc_reset(fdc)
- fdc_p fdc;
+fdc_reset(fdc_p fdc)
{
fdcu_t fdcu = fdc->fdcu;
@@ -643,26 +807,26 @@ fdc_reset(fdc)
outb(fdc->baseport + FDOUT, fdc->fdout);
TRACE1("[0x%x->FDOUT]", fdc->fdout);
- /* after a reset, silently believe the FDC will accept commands */
- out_fdc(fdcu, NE7CMD_SPECIFY);
- out_fdc(fdcu, NE7_SPEC_1(3, 240));
- out_fdc(fdcu, NE7_SPEC_2(2, 0));
+ /* XXX after a reset, silently believe the FDC will accept commands */
+ (void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY,
+ NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
+ 0);
}
/****************************************************************************/
/* fdc in/out */
/****************************************************************************/
int
-in_fdc(fdcu)
- fdcu_t fdcu;
+in_fdc(fdcu_t fdcu)
{
int baseport = fdc_data[fdcu].baseport;
int i, j = 100000;
while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM))
!= (NE7_DIO|NE7_RQM) && j-- > 0)
- if (i == NE7_RQM) return -1;
+ if (i == NE7_RQM)
+ return fdc_err(fdcu, "ready for output in input");
if (j <= 0)
- return(-1);
+ return fdc_err(fdcu, "input ready timeout");
#ifdef DEBUG
i = inb(baseport+FDDATA);
TRACE1("[FDDATA->0x%x]", (unsigned char)i);
@@ -672,10 +836,35 @@ in_fdc(fdcu)
#endif
}
+/*
+ * fd_in: Like in_fdc, but allows you to see if it worked.
+ */
int
-out_fdc(fdcu, x)
- fdcu_t fdcu;
- int x;
+fd_in(fdcu_t fdcu, int *ptr)
+{
+ int baseport = fdc_data[fdcu].baseport;
+ int i, j = 100000;
+ while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM))
+ != (NE7_DIO|NE7_RQM) && j-- > 0)
+ if (i == NE7_RQM)
+ return fdc_err(fdcu, "ready for output in input");
+ if (j <= 0)
+ return fdc_err(fdcu, "input ready timeout");
+#ifdef DEBUG
+ i = inb(baseport+FDDATA);
+ TRACE1("[FDDATA->0x%x]", (unsigned char)i);
+ *ptr = i;
+ return 0;
+#else
+ i = inb(baseport+FDDATA);
+ if (ptr)
+ *ptr = i;
+ return 0;
+#endif
+}
+
+int
+out_fdc(fdcu_t fdcu, int x)
{
int baseport = fdc_data[fdcu].baseport;
int i;
@@ -683,12 +872,12 @@ out_fdc(fdcu, x)
/* Check that the direction bit is set */
i = 100000;
while ((inb(baseport+FDSTS) & NE7_DIO) && i-- > 0);
- if (i <= 0) return (-1); /* Floppy timed out */
+ if (i <= 0) return fdc_err(fdcu, "direction bit not set");
/* Check that the floppy controller is ready for a command */
i = 100000;
while ((inb(baseport+FDSTS) & NE7_RQM) == 0 && i-- > 0);
- if (i <= 0) return (-1); /* Floppy timed out */
+ if (i <= 0) return fdc_err(fdcu, "output ready timeout");
/* Send the command and return */
outb(baseport+FDDATA, x);
@@ -700,9 +889,7 @@ out_fdc(fdcu, x)
/* fdopen/fdclose */
/****************************************************************************/
int
-Fdopen(dev, flags)
- dev_t dev;
- int flags;
+Fdopen(dev_t dev, int flags)
{
fdu_t fdu = FDUNIT(minor(dev));
int type = FDTYPE(minor(dev));
@@ -777,16 +964,23 @@ Fdopen(dev, flags)
set_motor(fdc->fdcu, fd_data[fdu].fdsu, TURNON);
if (flags & FWRITE) {
- /* Check to make sure the diskette */
- /* is writable */
- out_fdc(fdc->fdcu, NE7CMD_SENSED);
- out_fdc(fdc->fdcu, fdu);
- st3 = in_fdc(fdc->fdcu);
- if(st3 & NE7_ST3_WP) {
- printf("fd%d: write protected\n", fdu);
- set_motor(fdc->fdcu, fd_data[fdu].fdsu, TURNOFF);
- return(EPERM);
+ /*
+ * Check to make sure the diskette is writable:
+ */
+ int err = 0;
+
+ if (fd_sense_drive_status(fdc, &st3) != 0)
+ err = EIO;
+ else if ( (st3 & NE7_ST3_WP) )
+ {
+ printf("fd%d: drive is write protected.\n", fdu);
+ err = ENXIO;
}
+
+ if (err) {
+ set_motor(fdc->fdcu, fd_data[fdu].fdsu, TURNOFF);
+ return err;
+ }
}
set_motor(fdc->fdcu, fd_data[fdu].fdsu, TURNOFF);
@@ -798,9 +992,7 @@ Fdopen(dev, flags)
}
int
-fdclose(dev, flags)
- dev_t dev;
- int flags;
+fdclose(dev_t dev, int flags)
{
fdu_t fdu = FDUNIT(minor(dev));
@@ -853,7 +1045,8 @@ fdstrategy(struct buf *bp)
#endif
if (!(bp->b_flags & B_FORMAT)) {
if ((fdu >= NFD) || (bp->b_blkno < 0)) {
- printf("fdstrat: fdu = %d, blkno = %lu, bcount = %ld\n",
+ printf(
+ "fdstrat: fd%d: bad request blkno = %lu, bcount = %ld\n",
fdu, (u_long)bp->b_blkno, bp->b_bcount);
bp->b_error = EINVAL;
bp->b_flags |= B_ERROR;
@@ -903,8 +1096,7 @@ bad:
* will pick up our work when the present work completes *
\***************************************************************/
static void
-fdstart(fdcu)
- fdcu_t fdcu;
+fdstart(fdcu_t fdcu)
{
int s;
@@ -1005,9 +1197,7 @@ fdintr(fdcu_t fdcu)
* if it returns a non zero value, it should be called again immediatly *
\***********************************************************************/
static int
-fdstate(fdcu, fdc)
- fdcu_t fdcu;
- fdc_p fdc;
+fdstate(fdcu_t fdcu, fdc_p fdc)
{
int read, format, head, sec = 0, i = 0, sectrac, st0, cyl, st3;
unsigned long blknum;
@@ -1092,7 +1282,9 @@ fdstate(fdcu, fdc)
fdc->state = SEEKCOMPLETE;
break;
}
- if(out_fdc(fdcu, NE7CMD_SEEK) < 0) /* Seek function */
+ if (fd_cmd(fdcu, 3, NE7CMD_SEEK,
+ fd->fdsu, bp->b_cylin * fd->ft->steptrac,
+ 0))
{
/*
* seek command not accepted, looks like
@@ -1101,9 +1293,7 @@ fdstate(fdcu, fdc)
fdc->retry = 6; /* try a reset */
return(retrier(fdcu));
}
- out_fdc(fdcu, fd->fdsu); /* Drive number */
- out_fdc(fdcu, bp->b_cylin * fd->ft->steptrac);
- fd->track = -2;
+ fd->track = FD_NO_TRACK;
fdc->state = SEEKWAIT;
return(0); /* will return later */
case SEEKWAIT:
@@ -1113,37 +1303,63 @@ fdstate(fdcu, fdc)
return(0); /* will return later */
case SEEKCOMPLETE : /* SEEK DONE, START DMA */
/* Make sure seek really happened*/
- if(fd->track == -2)
+ if(fd->track == FD_NO_TRACK)
{
int descyl = bp->b_cylin * fd->ft->steptrac;
do {
- out_fdc(fdcu, NE7CMD_SENSEI);
- st0 = in_fdc(fdcu);
- cyl = in_fdc(fdcu);
/*
- * if this was a "ready changed" interrupt,
- * fetch status again (can happen after
- * enabling controller from reset state)
+ * This might be a "ready changed" interrupt,
+ * which cannot really happen since the
+ * RDY pin is hardwired to + 5 volts. This
+ * generally indicates a "bouncing" intr
+ * line, so do one of the following:
+ *
+ * When running on an enhanced FDC that is
+ * known to not go stuck after responding
+ * with INVALID, fetch all interrupt states
+ * until seeing either an INVALID or a
+ * real interrupt condition.
+ *
+ * When running on a dumb old NE765, give
+ * up immediately. The controller will
+ * provide up to four dummy RC interrupt
+ * conditions right after reset (for the
+ * corresponding four drives), so this is
+ * our only chance to get notice that it
+ * was not the FDC that caused the interrupt.
*/
+ if (fd_sense_int(fdc, &st0, &cyl)
+ == FD_NOT_VALID)
+ return 0;
+ if(fdc->fdct == FDC_NE765
+ && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC)
+ return 0; /* hope for a real intr */
} while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
+
if (0 == descyl)
{
+ int failed = 0;
/*
* seek to cyl 0 requested; make sure we are
* really there
*/
- out_fdc(fdcu, NE7CMD_SENSED);
- out_fdc(fdcu, fdu);
- st3 = in_fdc(fdcu);
+ if (fd_sense_drive_status(fdc, &st3))
+ failed = 1;
if ((st3 & NE7_ST3_T0) == 0) {
printf(
"fd%d: Seek to cyl 0, but not really there (ST3 = %b)\n",
fdu, st3, NE7_ST3BITS);
+ failed = 1;
+ }
+
+ if (failed)
+ {
if(fdc->retry < 3)
fdc->retry = 3;
return(retrier(fdcu));
}
}
+
if (cyl != descyl)
{
printf(
@@ -1170,14 +1386,12 @@ fdstate(fdcu, fdc)
if(format || !read)
{
/* make sure the drive is writable */
- if(out_fdc(fdcu, NE7CMD_SENSED) < 0)
+ if(fd_sense_drive_status(fdc, &st3) != 0)
{
/* stuck controller? */
fdc->retry = 6; /* reset the beast */
return(retrier(fdcu));
}
- out_fdc(fdcu, fdu);
- st3 = in_fdc(fdcu);
if(st3 & NE7_ST3_WP)
{
/*
@@ -1202,48 +1416,56 @@ fdstate(fdcu, fdc)
if(format)
{
/* formatting */
- if(out_fdc(fdcu, NE7CMD_FORMAT) < 0)
+ if(fd_cmd(fdcu, 6,
+ NE7CMD_FORMAT,
+ head << 2 | fdu,
+ finfo->fd_formb_secshift,
+ finfo->fd_formb_nsecs,
+ finfo->fd_formb_gaplen,
+ finfo->fd_formb_fillbyte,
+ 0))
{
/* controller fell over */
fdc->retry = 6;
return(retrier(fdcu));
}
- out_fdc(fdcu, head << 2 | fdu);
- out_fdc(fdcu, finfo->fd_formb_secshift);
- out_fdc(fdcu, finfo->fd_formb_nsecs);
- out_fdc(fdcu, finfo->fd_formb_gaplen);
- out_fdc(fdcu, finfo->fd_formb_fillbyte);
}
else
{
- if ((read && out_fdc(fdcu, NE7CMD_READ) < 0)
- || (!read /* i.e., write */
- && out_fdc(fdcu, NE7CMD_WRITE) < 0))
+ if (fd_cmd(fdcu, 9,
+ (read ? NE7CMD_READ : NE7CMD_WRITE),
+ head << 2 | fdu, /* head & unit */
+ fd->track, /* track */
+ head,
+ sec, /* sector + 1 */
+ fd->ft->secsize, /* sector size */
+ sectrac, /* sectors/track */
+ fd->ft->gap, /* gap size */
+ fd->ft->datalen, /* data length */
+ 0))
{
/* the beast is sleeping again */
fdc->retry = 6;
return(retrier(fdcu));
}
- out_fdc(fdcu, head << 2 | fdu); /* head & unit */
- out_fdc(fdcu, fd->track); /* track */
- out_fdc(fdcu, head);
- out_fdc(fdcu, sec); /* sector XXX +1? */
- out_fdc(fdcu, fd->ft->secsize); /* sector size */
- out_fdc(fdcu, sectrac); /* sectors/track */
- out_fdc(fdcu, fd->ft->gap); /* gap size */
- out_fdc(fdcu, fd->ft->datalen); /* data length */
}
fdc->state = IOCOMPLETE;
timeout(fd_timeout, (caddr_t)fdcu, hz);
return(0); /* will return later */
case IOCOMPLETE: /* IO DONE, post-analyze */
untimeout(fd_timeout, (caddr_t)fdcu);
- for(i=0;i<7;i++)
+
+ if (fd_read_status(fdc, fd->fdsu))
{
- fdc->status[i] = in_fdc(fdcu);
- }
+ if (fdc->retry < 6)
+ fdc->retry = 6; /* force a reset */
+ return retrier(fdcu);
+ }
+
fdc->state = IOTIMEDOUT;
+
/* FALLTHROUGH */
+
case IOTIMEDOUT:
isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip,
format ? bp->b_bcount : fdblk, fdc->dmachan);
@@ -1299,13 +1521,14 @@ fdstate(fdcu, fdc)
fdc->state = STARTRECAL;
break;
case STARTRECAL:
- if(out_fdc(fdcu, NE7CMD_RECAL) < 0) /* Recalibrate Function */
+ if(fd_cmd(fdcu,
+ 2, NE7CMD_RECAL, fdu,
+ 0)) /* Recalibrate Function */
{
/* arrgl */
fdc->retry = 6;
return(retrier(fdcu));
}
- out_fdc(fdcu, fdu);
fdc->state = RECALWAIT;
return(0); /* will return later */
case RECALWAIT:
@@ -1315,14 +1538,14 @@ fdstate(fdcu, fdc)
return(0); /* will return later */
case RECALCOMPLETE:
do {
- out_fdc(fdcu, NE7CMD_SENSEI);
- st0 = in_fdc(fdcu);
- cyl = in_fdc(fdcu);
/*
- * if this was a "ready changed" interrupt,
- * fetch status again (can happen after
- * enabling controller from reset state)
+ * See SEEKCOMPLETE for a comment on this:
*/
+ if (fd_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID)
+ return 0;
+ if(fdc->fdct == FDC_NE765
+ && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC)
+ return 0; /* hope for a real intr */
} while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
if ((st0 & NE7_ST0_IC) != NE7_ST0_IC_NT || cyl != 0)
{
@@ -1357,22 +1580,15 @@ fdstate(fdcu, fdc)
fdc->state = STARTRECAL;
return(1); /* will return immediatly */
default:
- printf("Unexpected FD int->");
- if(out_fdc(fdcu, NE7CMD_SENSEI) < 0)
+ printf("fdc%d: Unexpected FD int->", fdcu);
+ if (fd_sense_int(fdc, &st0, &cyl) != 0)
{
printf("[controller is dead now]\n");
return(0);
}
- st0 = in_fdc(fdcu);
- cyl = in_fdc(fdcu);
printf("ST0 = %x, PCN = %x\n", st0, cyl);
- out_fdc(fdcu, NE7CMD_READID);
- out_fdc(fdcu, fd->fdsu);
- for(i=0;i<7;i++) {
- fdc->status[i] = in_fdc(fdcu);
- }
- if(fdc->status[0] != -1)
- printf("intr status :%lx %lx %lx %lx %lx %lx %lx\n",
+ if (fd_read_status(fdc, fd->fdsu) == 0)
+ printf("FDC status :%lx %lx %lx %lx %lx %lx %lx\n",
fdc->status[0],
fdc->status[1],
fdc->status[2],
@@ -1381,7 +1597,7 @@ fdstate(fdcu, fdc)
fdc->status[5],
fdc->status[6] );
else
- printf("FDC timed out\n");
+ printf("No status available\n");
return(0);
}
return(1); /* Come back immediatly to new state */
@@ -1423,11 +1639,18 @@ retrier(fdcu)
fdc->fd->skip / DEV_BSIZE,
(struct disklabel *)NULL);
bp->b_dev = sav_b_dev;
- printf(" (ST0 %b ", fdc->status[0], NE7_ST0BITS);
- printf(" ST1 %b ", fdc->status[1], NE7_ST1BITS);
- printf(" ST2 %b ", fdc->status[2], NE7_ST2BITS);
- printf("cyl %ld hd %ld sec %ld)\n",
- fdc->status[3], fdc->status[4], fdc->status[5]);
+ if (fdc->flags & FDC_STAT_VALID)
+ {
+ printf(
+ " (ST0 %b ST1 %b ST2 %b cyl %ld hd %ld sec %ld)\n",
+ fdc->status[0], NE7_ST0BITS,
+ fdc->status[1], NE7_ST1BITS,
+ fdc->status[2], NE7_ST2BITS,
+ fdc->status[3], fdc->status[4],
+ fdc->status[5]);
+ }
+ else
+ printf(" (No status)\n");
}
bp->b_flags |= B_ERROR;
bp->b_error = EIO;
diff --git a/sys/isa/fdc.h b/sys/isa/fdc.h
index 950ef2346e9f..0216b7aa2e2e 100644
--- a/sys/isa/fdc.h
+++ b/sys/isa/fdc.h
@@ -31,10 +31,15 @@
* SUCH DAMAGE.
*
* from: @(#)fd.c 7.4 (Berkeley) 5/25/91
- * $Id: fdc.h,v 1.3 1994/09/17 16:56:07 davidg Exp $
+ * $Id: fdc.h,v 1.4 1994/10/10 01:12:26 phk Exp $
*
*/
+enum fdc_type
+{
+ FDC_NE765, FDC_I82077, FDC_NE72065, FDC_UNKNOWN = -1
+};
+
/***********************************************************************\
* Per controller structure. *
@@ -48,13 +53,16 @@ struct fdc_data
#define FDC_ATTACHED 0x01
#define FDC_HASFTAPE 0x02
#define FDC_TAPE_BUSY 0x04
+#define FDC_STAT_VALID 0x08
struct fd_data *fd;
int fdu; /* the active drive */
int state;
int retry;
int fdout; /* mirror of the w/o digital output reg */
u_long status[7]; /* copy of the registers */
- struct buf head; /* Head of buf chain */
+ enum fdc_type fdct; /* chip version of FDC */
+ int fdc_errs; /* number of logged errors */
+ struct buf head; /* Head of buf chain */
};
/***********************************************************************\
@@ -70,6 +78,7 @@ typedef int fdcu_t;
typedef int fdsu_t;
typedef struct fd_data *fd_p;
typedef struct fdc_data *fdc_p;
+typedef enum fdc_type fdc_t;
-#define FDUNIT(s) (((s)>>6)&03)
-#define FDTYPE(s) ((s)&077)
+#define FDUNIT(s) (((s)>>6)&03)
+#define FDTYPE(s) ((s)&077)
diff --git a/sys/isa/ic/nec765.h b/sys/isa/ic/nec765.h
index 9f93b705efe4..810e825bd66e 100644
--- a/sys/isa/ic/nec765.h
+++ b/sys/isa/ic/nec765.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*
* from: @(#)nec765.h 7.1 (Berkeley) 5/9/91
- * $Id: nec765.h,v 1.2 1993/10/16 13:48:50 rgrimes Exp $
+ * $Id: nec765.h,v 1.3 1994/09/17 16:56:10 davidg Exp $
*/
/*
@@ -121,6 +121,11 @@
#define NE7CMD_SCNLE 0xf9 /* scan less or equal */
#define NE7CMD_SCNGE 0xfd /* scan greater or equal */
+/*
+ * Enhanced controller commands:
+ */
+#define NE7CMD_VERSION 0x10 /* version (ok for all controllers) */
+
/*
* "specify" definitions