summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2004-08-20 15:14:25 +0000
committerphk <phk@FreeBSD.org>2004-08-20 15:14:25 +0000
commit91de1b896dea3928223e2531589b4c7c0d422ada (patch)
treeb948c22d12f559b0c58f576fc7da5d69acc1c8ef
parentca124b900b50e6642bad1e763cd2750ba4776602 (diff)
downloadFreeBSD-src-91de1b896dea3928223e2531589b4c7c0d422ada.zip
FreeBSD-src-91de1b896dea3928223e2531589b4c7c0d422ada.tar.gz
Rewrite of the floppy driver to make it MPsafe & GEOM friendly:
Centralize the fdctl_wr() function by adding the offset in the resource to the softc structure. Bugfix: Read the drive-change signal from the correct place: same place as the ctl register. Remove the cdevsw{} related code and implement a GEOM class. Ditch the state-engine and park a thread on each controller to service the queue. Make the interrupt FAST & MPSAFE since it is just a simple wakeup(9) call. Rely on a per controller mutex to protect the bioqueues. Grab GEOMs topology lock when we have to and Giant when ISADMA needs it. Since all access to the hardware is isolated in the per controller thread, the rest of the driver is lock & Giant free. Create a per-drive queue where requests are parked while the motor spins up. When the motor is running the requests are purged to the per controller queue. This allows requests to other drives to be serviced during spin-up. Only setup the motor-off timeout when we finish the last request on the queue and cancel it when a new request arrives. This fixes the bug in the old code where the motor turned off while we were still retrying a request. Make the "drive-change" work reliably. Probe the drive on first opens. Probe with a recal and a seek to cyl=1 to reset the drive change line and check again to see if we have a media. When we see the media disappear we destroy the geom provider, create a new one, and flag that autodetection should happen next time we see a media (unless a specific format is configured). Add sysctl tunables for a lot of drive related parameters. If you spend a lot of time waiting for floppies you can grab the i82078 pdf from Intels web-page and try tuning these. Add sysctl debug.fdc.debugflags which will enable various kinds of debugging printfs. Add central definitions of our well known floppy formats. Simplify datastructures for autoselection of format and call the code at the right times. Bugfix: Remove at least one piece of code which would have made 2.88M floppies not work. Use implied seeks on enhanced controllers. Use multisector transfers on all controllers. Increase ISADMA bounce buffers accordingly. Fall back to single sector when retrying. Reset retry count on every successful transaction. Sort functions in a more sensible order and generally tidy up a fair bit here and there. Assorted related fixes and adjustments in userland utilities. WORKAROUNDS: Do allow r/w opens of r/o media but refuse actual write operations. This is necessary until the p4::phk_bufwork branch gets integrated (This problem relates to remounting not reopening devices, see sys/*/*/${fs}_vfsops.c for details). Keep PC98's private copy of the old floppy driver compiling and presumably working (see below). TODO (planned) Move probing of drives until after interrupts/timeouts work (like for ATA/SCSI drives). TODO (unplanned) This driver should be made to work on PC98 as well. Test on YE-DATA PCMCIA floppy drive. Fix 2.88M media. This is a MT5 candidate (depends on the bioq_takefirst() addition).
-rw-r--r--sys/dev/fdc/fdc.c3044
-rw-r--r--sys/dev/fdc/fdc_acpi.c31
-rw-r--r--sys/dev/fdc/fdc_isa.c73
-rw-r--r--sys/dev/fdc/fdc_pccard.c23
-rw-r--r--sys/dev/fdc/fdcvar.h69
-rw-r--r--sys/sys/fdcio.h94
-rw-r--r--usr.sbin/fdcontrol/fdcontrol.c33
-rw-r--r--usr.sbin/fdformat/fdformat.c9
-rw-r--r--usr.sbin/fdread/fdutil.c139
9 files changed, 1484 insertions, 2031 deletions
diff --git a/sys/dev/fdc/fdc.c b/sys/dev/fdc/fdc.c
index d6008c3..d2c5588 100644
--- a/sys/dev/fdc/fdc.c
+++ b/sys/dev/fdc/fdc.c
@@ -1,4 +1,5 @@
/*-
+ * Copyright (c) 2004 Poul-Henning Kamp
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
@@ -46,6 +47,7 @@
* SUCH DAMAGE.
*
* from: @(#)fd.c 7.4 (Berkeley) 5/25/91
+ *
*/
#include <sys/cdefs.h>
@@ -62,36 +64,56 @@ __FBSDID("$FreeBSD$");
#include <sys/fdcio.h>
#include <sys/filio.h>
#include <sys/kernel.h>
+#include <sys/kthread.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/rman.h>
+#include <sys/sysctl.h>
#include <sys/systm.h>
+#include <geom/geom.h>
+
#include <machine/bus.h>
#include <machine/clock.h>
#include <machine/stdarg.h>
#include <isa/isavar.h>
#include <isa/isareg.h>
-#include <dev/fdc/fdcreg.h>
#include <dev/fdc/fdcvar.h>
#include <isa/rtc.h>
-#define FDBIO_FORMAT BIO_CMD2
+#include <dev/ic/nec765.h>
+
+/*
+ * Runtime configuration hints/flags
+ */
+
+/* configuration flags for fd */
+#define FD_TYPEMASK 0x0f /* drive type, matches enum
+ * fd_drivetype; on i386 machines, if
+ * given as 0, use RTC type for fd0
+ * and fd1 */
+#define FD_NO_CHLINE 0x10 /* drive does not support changeline
+ * aka. unit attention */
+#define FD_NO_PROBE 0x20 /* don't probe drive (seek test), just
+ * assume it is there */
-/* configuration flags for fdc */
-#define FDC_NO_FIFO (1 << 2) /* do not enable FIFO */
+/*
+ * Things that could conceiveably considered parameters or tweakables
+ */
/*
- * Stop retrying after this many DMA overruns. Since each retry takes
- * one revolution, with 300 rpm., 25 retries take approximately 5
- * seconds which the read attempt will block in case the DMA overrun
- * is persistent.
+ * Maximal number of bytes in a cylinder.
+ * This is used for ISADMA bouncebuffer allocation and sets the max
+ * xfersize we support.
+ *
+ * 2.88M format has 2 x 36 x 512.
*/
-#define FDC_DMAOV_MAX 25
+
+#define MAX_BYTES_PER_CYL (2 * 40 * 512)
/*
* Timeout value for the PIO loops to wait until the FDC main status
@@ -105,230 +127,216 @@ __FBSDID("$FreeBSD$");
#define FDSTS_TIMEOUT 100000
/*
- * Number of subdevices that can be used for different density types.
+ * After this many errors, stop whining. Close will reset this count.
*/
-#define NUMDENS 16
-
-#define FDBIO_RDSECTID BIO_CMD1
+#define FDC_ERRMAX 100 /* do not log more */
/*
- * List of native drive densities. Order must match enum fd_drivetype
- * in <sys/fdcio.h>. Upon attaching the drive, each of the
- * programmable subdevices is initialized with the native density
- * definition.
+ * AutoDensity search lists for each drive type.
*/
-static struct fd_type fd_native_types[] =
-{
-{ 0 }, /* FDT_NONE */
-{ 9,2,0xFF,0x2A,40, 720,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* FDT_360K */
-{ 15,2,0xFF,0x1B,80,2400,FDC_500KBPS,2,0x54,1,0,FL_MFM }, /* FDT_12M */
-{ 9,2,0xFF,0x20,80,1440,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* FDT_720K */
-{ 18,2,0xFF,0x1B,80,2880,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* FDT_144M */
-#if 0 /* we currently don't handle 2.88 MB */
-{ 36,2,0xFF,0x1B,80,5760,FDC_1MBPS, 2,0x4C,1,1,FL_MFM|FL_PERPND } /*FDT_288M*/
-#else
-{ 18,2,0xFF,0x1B,80,2880,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* FDT_144M */
-#endif
+
+static struct fd_type fd_searchlist_360k[] = {
+ { FDF_5_360 },
+ { 0 }
};
-/*
- * 360 KB 5.25" and 720 KB 3.5" drives don't have automatic density
- * selection, they just start out with their native density (or lose).
- * So 1.2 MB 5.25", 1.44 MB 3.5", and 2.88 MB 3.5" drives have their
- * respective lists of densities to search for.
- */
static struct fd_type fd_searchlist_12m[] = {
-{ 15,2,0xFF,0x1B,80,2400,FDC_500KBPS,2,0x54,1,0,FL_MFM }, /* 1.2M */
-{ 9,2,0xFF,0x23,40, 720,FDC_300KBPS,2,0x50,1,0,FL_MFM|FL_2STEP }, /* 360K */
-{ 9,2,0xFF,0x20,80,1440,FDC_300KBPS,2,0x50,1,0,FL_MFM }, /* 720K */
+ { FDF_5_1200 | FL_AUTO },
+ { FDF_5_360 | FL_2STEP | FL_AUTO},
+ { 0 }
+};
+
+static struct fd_type fd_searchlist_720k[] = {
+ { FDF_3_720 },
+ { 0 }
};
static struct fd_type fd_searchlist_144m[] = {
-{ 18,2,0xFF,0x1B,80,2880,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* 1.44M */
-{ 9,2,0xFF,0x20,80,1440,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* 720K */
+ { FDF_3_1440 | FL_AUTO},
+ { FDF_3_720 | FL_AUTO},
+ { 0 }
};
-/* We search for 1.44M first since this is the most common case. */
static struct fd_type fd_searchlist_288m[] = {
-{ 18,2,0xFF,0x1B,80,2880,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* 1.44M */
+ { FDF_3_1440 | FL_AUTO },
#if 0
-{ 36,2,0xFF,0x1B,80,5760,FDC_1MBPS, 2,0x4C,1,1,FL_MFM|FL_PERPND } /* 2.88M */
+ { FDF_3_2880 | FL_AUTO }, /* XXX: probably doesn't work */
#endif
-{ 9,2,0xFF,0x20,80,1440,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* 720K */
+ { FDF_3_720 | FL_AUTO},
+ { 0 }
};
-#define MAX_SEC_SIZE (128 << 3)
-#define MAX_CYLINDER 85 /* some people really stress their drives
- * up to cyl 82 */
-#define MAX_HEAD 1
+/*
+ * Order must match enum fd_drivetype in <sys/fdcio.h>.
+ */
+static struct fd_type *fd_native_types[] = {
+ NULL, /* FDT_NONE */
+ fd_searchlist_360k, /* FDT_360K */
+ fd_searchlist_12m, /* FDT_12M */
+ fd_searchlist_720k, /* FDT_720K */
+ fd_searchlist_144m, /* FDT_144M */
+ fd_searchlist_288m, /* FDT_288M */
+};
-devclass_t fdc_devclass;
+/*
+ * Internals start here
+ */
+
+/* registers */
+#define FDOUT 2 /* Digital Output Register (W) */
+#define FDO_FDSEL 0x03 /* floppy device select */
+#define FDO_FRST 0x04 /* floppy controller reset */
+#define FDO_FDMAEN 0x08 /* enable floppy DMA and Interrupt */
+#define FDO_MOEN0 0x10 /* motor enable drive 0 */
+#define FDO_MOEN1 0x20 /* motor enable drive 1 */
+#define FDO_MOEN2 0x40 /* motor enable drive 2 */
+#define FDO_MOEN3 0x80 /* motor enable drive 3 */
+
+#define FDSTS 4 /* NEC 765 Main Status Register (R) */
+#define FDDATA 5 /* NEC 765 Data Register (R/W) */
+#define FDCTL 7 /* Control Register (W) */
+
+/*
+ * this is the secret PIO data port (offset from base)
+ */
+#define FDC_YE_DATAPORT 6
+
+#define FDI_DCHG 0x80 /* diskette has been changed */
+ /* requires drive and motor being selected */
+ /* is cleared by any step pulse to drive */
+
+/*
+ * We have two private BIO commands for formatting and sector-id reading
+ */
+#define BIO_PROBE BIO_CMD0
+#define BIO_RDID BIO_CMD1
+#define BIO_FMT BIO_CMD2
/*
* Per drive structure (softc).
*/
struct fd_data {
+ u_char *fd_ioptr; /* IO pointer */
+ u_int fd_iosize; /* Size of IO chunks */
+ u_int fd_iocount; /* Outstanding requests */
struct fdc_data *fdc; /* pointer to controller structure */
int fdsu; /* this units number on this controller */
enum fd_drivetype type; /* drive type */
struct fd_type *ft; /* pointer to current type descriptor */
- struct fd_type fts[NUMDENS]; /* type descriptors */
+ struct fd_type fts; /* type descriptors */
+ int sectorsize;
int flags;
-#define FD_OPEN 0x01 /* it's open */
-#define FD_NONBLOCK 0x02 /* O_NONBLOCK set */
-#define FD_ACTIVE 0x04 /* it's active */
-#define FD_MOTOR 0x08 /* motor should be on */
-#define FD_MOTOR_WAIT 0x10 /* motor coming up */
-#define FD_UA 0x20 /* force unit attention */
- int skip;
- int hddrv;
-#define FD_NO_TRACK -2
+#define FD_WP (1<<0) /* Write protected */
+#define FD_MOTOR (1<<1) /* motor should be on */
+#define FD_MOTORWAIT (1<<2) /* motor should be on */
+#define FD_EMPTY (1<<3) /* no media */
+#define FD_NEWDISK (1<<4) /* media changed */
+#define FD_ISADMA (1<<5) /* isa dma started */
int track; /* where we think the head is */
- int options; /* user configurable options, see fdcio.h */
- struct callout_handle toffhandle;
- struct callout_handle tohandle;
- struct devstat *device_stats;
- struct cdev *masterdev;
+#define FD_NO_TRACK -2
+ int options; /* FDOPT_* */
+ struct callout toffhandle;
+ struct callout tohandle;
+ struct g_geom *fd_geom;
+ struct g_provider *fd_provider;
device_t dev;
- fdu_t fdu;
+ struct bio_queue_head fd_bq;
};
-struct fdc_ivars {
- int fdunit;
- int fdtype;
-};
+#define FD_NOT_VALID -2
-static devclass_t fd_devclass;
+static driver_intr_t fdc_intr;
+static void fdc_reset(struct fdc_data *);
-/* configuration flags for fd */
-#define FD_TYPEMASK 0x0f /* drive type, matches enum
- * fd_drivetype; on i386 machines, if
- * given as 0, use RTC type for fd0
- * and fd1 */
-#define FD_DTYPE(flags) ((flags) & FD_TYPEMASK)
-#define FD_NO_CHLINE 0x10 /* drive does not support changeline
- * aka. unit attention */
-#define FD_NO_PROBE 0x20 /* don't probe drive (seek test), just
- * assume it is there */
+SYSCTL_NODE(_debug, OID_AUTO, fdc, CTLFLAG_RW, 0, "fdc driver");
-/*
- * Throughout this file the following conventions will be used:
- *
- * fd is a pointer to the fd_data struct for the drive in question
- * fdc is a pointer to the fdc_data struct for the controller
- * fdu is the floppy drive unit number
- * fdcu is the floppy controller unit number
- * fdsu is the floppy drive unit number on that controller. (sub-unit)
- */
+static int fifo_threshold = 8;
+SYSCTL_INT(_debug_fdc, OID_AUTO, fifo, CTLFLAG_RW, &fifo_threshold, 0,
+ "FIFO threshold setting");
-/*
- * Function declarations, same (chaotic) order as they appear in the
- * file. Re-ordering is too late now, it would only obfuscate the
- * diffs against old and offspring versions (like the PC98 one).
- *
- * Anyone adding functions here, please keep this sequence the same
- * as below -- makes locating a particular function in the body much
- * easier.
- */
-static u_int8_t fdsts_rd(fdc_p);
-static void fddata_wr(fdc_p, u_int8_t);
-static u_int8_t fddata_rd(fdc_p);
-#if 0
-static u_int8_t fdin_rd(fdc_p);
-#endif
-static int fdc_err(struct fdc_data *, const char *);
-static int enable_fifo(fdc_p fdc);
-static int fd_sense_drive_status(fdc_p, int *);
-static int fd_sense_int(fdc_p, int *, int *);
-static int fd_read_status(fdc_p);
-static int fd_probe(device_t);
-static int fd_attach(device_t);
-static int fd_detach(device_t);
-static void set_motor(struct fdc_data *, int, int);
-# define TURNON 1
-# define TURNOFF 0
-static timeout_t fd_turnoff;
-static timeout_t fd_motor_on;
-static void fd_turnon(struct fd_data *);
-static void fdc_reset(fdc_p);
-static int fd_in(struct fdc_data *, int *);
-static int out_fdc(struct fdc_data *, int);
-static d_open_t fdopen;
-static d_close_t fdclose;
-static d_strategy_t fdstrategy;
-static void fdstart(struct fdc_data *);
-static timeout_t fd_iotimeout;
-static timeout_t fd_pseudointr;
-static driver_intr_t fdc_intr;
-static int fdcpio(fdc_p, long, caddr_t, u_int);
-static int fdautoselect(struct cdev *);
-static int fdstate(struct fdc_data *);
-static int retrier(struct fdc_data *);
-static void fdbiodone(struct bio *);
-static int fdmisccmd(struct cdev *, u_int, void *);
-static d_ioctl_t fdioctl;
-
-static int fifo_threshold = 8; /* XXX: should be accessible via sysctl */
-
-#ifdef FDC_DEBUG
-/* CAUTION: fd_debug causes huge amounts of logging output */
-static int volatile fd_debug = 0;
-#define TRACE0(arg) do { if (fd_debug) printf(arg); } while (0)
-#define TRACE1(arg1, arg2) do { if (fd_debug) printf(arg1, arg2); } while (0)
-#else /* FDC_DEBUG */
-#define TRACE0(arg) do { } while (0)
-#define TRACE1(arg1, arg2) do { } while (0)
-#endif /* FDC_DEBUG */
+static int debugflags = 0;
+SYSCTL_INT(_debug_fdc, OID_AUTO, debugflags, CTLFLAG_RW, &debugflags, 0,
+ "Debug flags");
+
+static int retries = 10;
+SYSCTL_INT(_debug_fdc, OID_AUTO, retries, CTLFLAG_RW, &retries, 0,
+ "Number of retries to attempt");
+
+static int spec1 = 0xaf;
+SYSCTL_INT(_debug_fdc, OID_AUTO, spec1, CTLFLAG_RW, &spec1, 0,
+ "Specification byte one (step-rate + head unload)");
+
+static int spec2 = 0x10;
+SYSCTL_INT(_debug_fdc, OID_AUTO, spec2, CTLFLAG_RW, &spec2, 0,
+ "Specification byte two (head load time + no-dma)");
+
+static int settle;
+SYSCTL_INT(_debug_fdc, OID_AUTO, settle, CTLFLAG_RW, &settle, 0,
+ "Head settling time in sec/hz");
+
+static void
+fdprinttype(struct fd_type *ft)
+{
+
+ printf("(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,0x%x)",
+ ft->sectrac, ft->secsize, ft->datalen, ft->gap, ft->tracks,
+ ft->size, ft->trans, ft->heads, ft->f_gap, ft->f_inter,
+ ft->offset_side2, ft->flags);
+}
+
+static void
+fdsettype(struct fd_data *fd, struct fd_type *ft)
+{
+ fd->ft = ft;
+ ft->size = ft->sectrac * ft->heads * ft->tracks;
+ fd->sectorsize = 128 << fd->ft->secsize;
+}
/*
* Bus space handling (access to low-level IO).
*/
-void
-fdout_wr(fdc_p fdc, u_int8_t v)
+static void
+fdctl_wr(struct fdc_data *fdc, u_int8_t v)
{
+
+ bus_space_write_1(fdc->ctlt, fdc->ctlh, fdc->ctl_off, v);
+}
+
+static void
+fdout_wr(struct fdc_data *fdc, u_int8_t v)
+{
+
bus_space_write_1(fdc->portt, fdc->porth, FDOUT+fdc->port_off, v);
}
static u_int8_t
-fdsts_rd(fdc_p fdc)
+fdsts_rd(struct fdc_data *fdc)
{
+
return bus_space_read_1(fdc->portt, fdc->porth, FDSTS+fdc->port_off);
}
static void
-fddata_wr(fdc_p fdc, u_int8_t v)
+fddata_wr(struct fdc_data *fdc, u_int8_t v)
{
+
bus_space_write_1(fdc->portt, fdc->porth, FDDATA+fdc->port_off, v);
}
static u_int8_t
-fddata_rd(fdc_p fdc)
+fddata_rd(struct fdc_data *fdc)
{
+
return bus_space_read_1(fdc->portt, fdc->porth, FDDATA+fdc->port_off);
}
static u_int8_t
-fdin_rd(fdc_p fdc)
+fdin_rd(struct fdc_data *fdc)
{
- return bus_space_read_1(fdc->portt, fdc->porth, FDIN);
-}
-static struct cdevsw fd_cdevsw = {
- .d_version = D_VERSION,
- .d_open = fdopen,
- .d_close = fdclose,
- .d_read = physread,
- .d_write = physwrite,
- .d_ioctl = fdioctl,
- .d_strategy = fdstrategy,
- .d_name = "fd",
- .d_flags = D_DISK | D_NEEDGIANT,
-};
+ return bus_space_read_1(fdc->ctlt, fdc->ctlh, fdc->ctl_off);
+}
-/*
- * Auxiliary functions. Well, some only. Others are scattered
- * throughout the entire file.
- */
static int
fdc_err(struct fdc_data *fdc, const char *s)
{
@@ -341,121 +349,167 @@ fdc_err(struct fdc_data *fdc, const char *s)
"logging any more\n");
}
- return FD_FAILED;
+ return (1);
}
/*
- * 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 ...
+ * FDC IO functions, take care of the main status register, timeout
+ * in case the desired status bits are never set.
+ *
+ * These PIO loops initially start out with short delays between
+ * each iteration in the expectation that the required condition
+ * is usually met quickly, so it can be handled immediately.
*/
-int
-fd_cmd(struct fdc_data *fdc, int n_out, ...)
+static int
+fdc_in(struct fdc_data *fdc, int *ptr)
{
- u_char cmd;
+ int i, j, step;
+
+ step = 1;
+ for (j = 0; j < FDSTS_TIMEOUT; j += step) {
+ i = fdsts_rd(fdc) & (NE7_DIO | NE7_RQM);
+ if (i == (NE7_DIO|NE7_RQM)) {
+ i = fddata_rd(fdc);
+ if (ptr)
+ *ptr = i;
+ return (0);
+ }
+ if (i == NE7_RQM)
+ return (fdc_err(fdc, "ready for output in input\n"));
+ step += step;
+ DELAY(step);
+ }
+ return (fdc_err(fdc, bootverbose? "input ready timeout\n": 0));
+}
+
+static int
+fdc_out(struct fdc_data *fdc, int x)
+{
+ int i, j, step;
+
+ step = 1;
+ for (j = 0; j < FDSTS_TIMEOUT; j += step) {
+ i = fdsts_rd(fdc) & (NE7_DIO | NE7_RQM);
+ if (i == NE7_RQM) {
+ fddata_wr(fdc, x);
+ return (0);
+ }
+ if (i == (NE7_DIO|NE7_RQM))
+ return (fdc_err(fdc, "ready for input in output\n"));
+ step += step;
+ DELAY(step);
+ }
+ return (fdc_err(fdc, bootverbose? "output ready timeout\n": 0));
+}
+
+/*
+ * fdc_cmd: Send a command to the chip.
+ * Takes a varargs with this structure:
+ * # of output bytes
+ * output bytes as int [...]
+ * # of input bytes
+ * input bytes as int* [...]
+ */
+static int
+fdc_cmd(struct fdc_data *fdc, int n_out, ...)
+{
+ u_char cmd = 0;
int n_in;
- int n;
+ int n, i;
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(fdc, va_arg(ap, int)) < 0)
- {
+ for (n = 0; n < n_out; n++) {
+ i = va_arg(ap, int);
+ if (n == 0)
+ cmd = i;
+ if (fdc_out(fdc, i) < 0) {
char msg[50];
snprintf(msg, sizeof(msg),
"cmd %x failed at out byte %d of %d\n",
cmd, n + 1, n_out);
+ fdc->flags |= FDC_NEEDS_RESET;
return fdc_err(fdc, msg);
}
}
n_in = va_arg(ap, int);
- for (n = 0; n < n_in; n++)
- {
+ for (n = 0; n < n_in; n++) {
int *ptr = va_arg(ap, int *);
- if (fd_in(fdc, ptr) < 0)
- {
+ if (fdc_in(fdc, ptr) < 0) {
char msg[50];
snprintf(msg, sizeof(msg),
"cmd %02x failed at in byte %d of %d\n",
cmd, n + 1, n_in);
+ fdc->flags |= FDC_NEEDS_RESET;
return fdc_err(fdc, msg);
}
}
-
- return 0;
+ return (0);
}
-static int
-enable_fifo(fdc_p fdc)
+static void
+fdc_reset(struct fdc_data *fdc)
{
- int i, j;
+ int i, r[10];
- if ((fdc->flags & FDC_HAS_FIFO) == 0) {
-
- /*
- * Cannot use fd_cmd the normal way here, since
- * this might be an invalid command. Thus we send the
- * first byte, and check for an early turn of data directon.
- */
-
- if (out_fdc(fdc, I8207X_CONFIGURE) < 0)
- return fdc_err(fdc, "Enable FIFO failed\n");
-
- /* If command is invalid, return */
- j = FDSTS_TIMEOUT;
- while ((i = fdsts_rd(fdc) & (NE7_DIO | NE7_RQM))
- != NE7_RQM && j-- > 0) {
- if (i == (NE7_DIO | NE7_RQM)) {
- fdc_reset(fdc);
- return FD_FAILED;
- }
- DELAY(1);
- }
- if (j<0 ||
- fd_cmd(fdc, 3,
- 0, (fifo_threshold - 1) & 0xf, 0, 0) < 0) {
- fdc_reset(fdc);
- return fdc_err(fdc, "Enable FIFO failed\n");
+ /* Try a reset, keep motor on */
+ fdout_wr(fdc, fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
+ DELAY(100);
+ /* enable FDC, but defer interrupts a moment */
+ fdout_wr(fdc, fdc->fdout & ~FDO_FDMAEN);
+ DELAY(100);
+ fdout_wr(fdc, fdc->fdout);
+
+ /* XXX after a reset, silently believe the FDC will accept commands */
+ if (fdc_cmd(fdc, 3, NE7CMD_SPECIFY, spec1, spec2, 0))
+ device_printf(fdc->fdc_dev, " SPECIFY failed in reset\n");
+
+ if (fdc->fdct == FDC_ENHANCED) {
+ if (fdc_cmd(fdc, 4,
+ I8207X_CONFIGURE,
+ 0,
+ 0x40 | /* Enable Implied Seek */
+ 0x10 | /* Polling disabled */
+ (fifo_threshold - 1), /* Fifo threshold */
+ 0x00, /* Precomp track */
+ 0))
+ device_printf(fdc->fdc_dev,
+ " CONFIGURE failed in reset\n");
+ if (debugflags & 1) {
+ if (fdc_cmd(fdc, 1,
+ 0x0e, /* DUMPREG */
+ 10, &r[0], &r[1], &r[2], &r[3], &r[4],
+ &r[5], &r[6], &r[7], &r[8], &r[9]))
+ device_printf(fdc->fdc_dev,
+ " DUMPREG failed in reset\n");
+ for (i = 0; i < 10; i++)
+ printf(" %02x", r[i]);
+ printf("\n");
}
- fdc->flags |= FDC_HAS_FIFO;
- return 0;
}
- if (fd_cmd(fdc, 4,
- I8207X_CONFIGURE, 0, (fifo_threshold - 1) & 0xf, 0, 0) < 0)
- return fdc_err(fdc, "Re-enable FIFO failed\n");
- return 0;
}
static int
-fd_sense_drive_status(fdc_p fdc, int *st3p)
+fdc_sense_drive(struct fdc_data *fdc, int *st3p)
{
int st3;
- if (fd_cmd(fdc, 2, NE7CMD_SENSED, fdc->fdu, 1, &st3))
- {
- return fdc_err(fdc, "Sense Drive Status failed\n");
- }
+ if (fdc_cmd(fdc, 2, NE7CMD_SENSED, fdc->fd->fdsu, 1, &st3))
+ return (fdc_err(fdc, "Sense Drive Status failed\n"));
if (st3p)
*st3p = st3;
-
- return 0;
+ return (0);
}
static int
-fd_sense_int(fdc_p fdc, int *st0p, int *cylp)
+fdc_sense_int(struct fdc_data *fdc, int *st0p, int *cylp)
{
int cyl, st0, ret;
- ret = fd_cmd(fdc, 1, NE7CMD_SENSEI, 1, &st0);
+ ret = fdc_cmd(fdc, 1, NE7CMD_SENSEI, 1, &st0);
if (ret) {
- (void)fdc_err(fdc,
- "sense intr err reading stat reg 0\n");
- return ret;
+ (void)fdc_err(fdc, "sense intr err reading stat reg 0\n");
+ return (ret);
}
if (st0p)
@@ -465,34 +519,25 @@ fd_sense_int(fdc_p fdc, int *st0p, int *cylp)
/*
* There doesn't seem to have been an interrupt.
*/
- return FD_NOT_VALID;
+ return (FD_NOT_VALID);
}
- if (fd_in(fdc, &cyl) < 0) {
+ if (fdc_in(fdc, &cyl) < 0)
return fdc_err(fdc, "can't get cyl num\n");
- }
if (cylp)
*cylp = cyl;
- return 0;
+ return (0);
}
-
static int
-fd_read_status(fdc_p fdc)
+fdc_read_status(struct fdc_data *fdc)
{
- int i, ret;
+ int i, ret, status;
for (i = ret = 0; i < 7; i++) {
- /*
- * XXX types are poorly chosen. Only bytes can be read
- * from the hardware, but fdc->status[] wants u_ints and
- * fd_in() gives ints.
- */
- int status;
-
- ret = fd_in(fdc, &status);
+ ret = fdc_in(fdc, &status);
fdc->status[i] = status;
if (ret != 0)
break;
@@ -506,6 +551,933 @@ fd_read_status(fdc_p fdc)
return ret;
}
+/*
+ * Select this drive
+ */
+static void
+fd_select(struct fd_data *fd)
+{
+ struct fdc_data *fdc;
+
+ /* XXX: lock controller */
+ fdc = fd->fdc;
+ fdc->fdout &= ~FDO_FDSEL;
+ fdc->fdout |= FDO_FDMAEN | FDO_FRST | fd->fdsu;
+ fdout_wr(fdc, fdc->fdout);
+}
+
+static void
+fd_turnon(void *arg)
+{
+ struct fd_data *fd;
+ struct bio *bp;
+ int once;
+
+ fd = arg;
+ mtx_lock(&fd->fdc->fdc_mtx);
+ fd->flags &= ~FD_MOTORWAIT;
+ fd->flags |= FD_MOTOR;
+ once = 0;
+ for (;;) {
+ bp = bioq_takefirst(&fd->fd_bq);
+ if (bp == NULL)
+ break;
+ bioq_disksort(&fd->fdc->head, bp);
+ once = 1;
+ }
+ mtx_unlock(&fd->fdc->fdc_mtx);
+ if (once)
+ wakeup(&fd->fdc->head);
+}
+
+static void
+fd_motor(struct fd_data *fd, int turnon)
+{
+ struct fdc_data *fdc;
+
+ fdc = fd->fdc;
+/*
+ mtx_assert(&fdc->fdc_mtx, MA_OWNED);
+*/
+ if (turnon) {
+ fd->flags |= FD_MOTORWAIT;
+ fdc->fdout |= (FDO_MOEN0 << fd->fdsu);
+ callout_reset(&fd->toffhandle, hz, fd_turnon, fd);
+ } else {
+ callout_drain(&fd->toffhandle);
+ fd->flags &= ~(FD_MOTOR|FD_MOTORWAIT);
+ fdc->fdout &= ~(FDO_MOEN0 << fd->fdsu);
+ }
+ fdout_wr(fdc, fdc->fdout);
+}
+
+static void
+fd_turnoff(void *xfd)
+{
+ struct fd_data *fd = xfd;
+
+ mtx_lock(&fd->fdc->fdc_mtx);
+ fd_motor(fd, 0);
+ mtx_unlock(&fd->fdc->fdc_mtx);
+}
+
+/*
+ * fdc_intr
+ *
+ * Keep calling the state machine until it returns a 0.
+ */
+static void
+fdc_intr(void *arg)
+{
+
+ wakeup(arg);
+}
+
+/*
+ * Magic pseudo-DMA initialization for YE FDC. Sets count and
+ * direction.
+ */
+#define SET_BCDR(fdc,wr,cnt,port) \
+ do { \
+ bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + port, \
+ ((cnt)-1) & 0xff); \
+ bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + port + 1, \
+ ((wr ? 0x80 : 0) | ((((cnt)-1) >> 8) & 0x7f))); \
+ } while (0)
+
+/*
+ * fdc_pio(): perform programmed IO read/write for YE PCMCIA floppy.
+ */
+static void
+fdc_pio(struct fdc_data *fdc)
+{
+ u_char *cptr;
+ struct bio *bp;
+ u_int count;
+
+ bp = fdc->bp;
+ cptr = fdc->fd->fd_ioptr;
+ count = fdc->fd->fd_iosize;
+
+ if (bp->bio_cmd == BIO_READ) {
+ SET_BCDR(fdc, 0, count, 0);
+ bus_space_read_multi_1(fdc->portt, fdc->porth, fdc->port_off +
+ FDC_YE_DATAPORT, cptr, count);
+ } else {
+ bus_space_write_multi_1(fdc->portt, fdc->porth, fdc->port_off +
+ FDC_YE_DATAPORT, cptr, count);
+ SET_BCDR(fdc, 0, count, 0);
+ }
+}
+
+static int
+fdc_biodone(struct fdc_data *fdc, int error)
+{
+ struct fd_data *fd;
+ struct bio *bp;
+
+ fd = fdc->fd;
+ bp = fdc->bp;
+
+ mtx_lock(&fdc->fdc_mtx);
+ if (--fd->fd_iocount == 0)
+ callout_reset(&fd->toffhandle, 4 * hz, fd_turnoff, fd);
+ fdc->bp = NULL;
+ fdc->fd = NULL;
+ mtx_unlock(&fdc->fdc_mtx);
+ if (bp->bio_to != NULL) {
+ if ((debugflags & 2) && fd->fdc->retry > 0)
+ printf("retries: %d\n", fd->fdc->retry);
+ g_io_deliver(bp, error);
+ return (0);
+ }
+ bp->bio_error = error;
+ bp->bio_flags |= BIO_DONE;
+ wakeup(bp);
+ return (0);
+}
+
+static int retry_line;
+
+static int
+fdc_worker(struct fdc_data *fdc)
+{
+ struct fd_data *fd;
+ struct bio *bp;
+ int i, nsect;
+ int st0, st3, cyl, mfm, steptrac, cylinder, descyl, sec;
+ int head;
+ static int need_recal;
+ struct fdc_readid *idp;
+ struct fd_formb *finfo;
+
+ /* Have we exhausted our retries ? */
+ bp = fdc->bp;
+ fd = fdc->fd;
+ if (bp != NULL &&
+ (fdc->retry >= retries || (fd->flags & FDOPT_NORETRY))) {
+ if ((debugflags & 4))
+ printf("Too many retries (EIO)\n");
+ return (fdc_biodone(fdc, EIO));
+ }
+
+ /* Disable ISADMA if we bailed while it was active */
+ if (fd != NULL && (fd->flags & FD_ISADMA)) {
+ mtx_lock(&Giant);
+ isa_dmadone(
+ bp->bio_cmd & BIO_READ ? ISADMA_READ : ISADMA_WRITE,
+ fd->fd_ioptr, fd->fd_iosize, fdc->dmachan);
+ mtx_unlock(&Giant);
+ fd->flags &= ~FD_ISADMA;
+ }
+
+ /* Unwedge the controller ? */
+ if (fdc->flags & FDC_NEEDS_RESET) {
+ fdc->flags &= ~FDC_NEEDS_RESET;
+ fdc_reset(fdc);
+ msleep(fdc, NULL, PRIBIO, "fdcrst", hz);
+ /* Discard results */
+ for (i = 0; i < 4; i++)
+ fdc_sense_int(fdc, &st0, &cyl);
+ /* All drives must recal */
+ need_recal = 0xf;
+ }
+
+ /* Pick up a request, if need be wait for it */
+ if (fdc->bp == NULL) {
+ mtx_lock(&fdc->fdc_mtx);
+ do {
+ fdc->bp = bioq_takefirst(&fdc->head);
+ if (fdc->bp == NULL)
+ msleep(&fdc->head, &fdc->fdc_mtx,
+ PRIBIO, "-", hz);
+ } while (fdc->bp == NULL);
+ mtx_unlock(&fdc->fdc_mtx);
+ bp = fdc->bp;
+ fd = fdc->fd = bp->bio_driver1;
+ fdc->retry = 0;
+ fd->fd_ioptr = bp->bio_data;
+ if (bp->bio_cmd & BIO_FMT) {
+ i = offsetof(struct fd_formb, fd_formb_cylno(0));
+ fd->fd_ioptr += i;
+ fd->fd_iosize = bp->bio_length - i;
+ }
+ }
+
+ /* Select drive, setup params */
+ fd_select(fd);
+ fdctl_wr(fdc, fd->ft->trans);
+
+ if (bp->bio_cmd & BIO_PROBE) {
+
+ if (!(fdin_rd(fdc) & FDI_DCHG) && !(fd->flags & FD_EMPTY))
+ return (fdc_biodone(fdc, 0));
+
+ /*
+ * Try to find out if we have a disk in the drive
+ *
+ * First recal, then seek to cyl#1, this clears the
+ * old condition on the disk change line so we can
+ * examine it for current status
+ */
+ if (debugflags & 0x40)
+ printf("New disk in probe\n");
+ fd->flags |= FD_NEWDISK;
+ retry_line = __LINE__;
+ if (fdc_cmd(fdc, 2, NE7CMD_RECAL, fd->fdsu, 0))
+ return (1);
+ msleep(fdc, NULL, PRIBIO, "fdrecal", hz);
+ retry_line = __LINE__;
+ if (fdc_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID)
+ return (1); /* XXX */
+ retry_line = __LINE__;
+ if ((st0 & 0xc0) || cyl != 0)
+ return (1);
+
+ /* Seek to track 1 */
+ retry_line = __LINE__;
+ if (fdc_cmd(fdc, 3, NE7CMD_SEEK, fd->fdsu, 1, 0))
+ return (1);
+ msleep(fdc, NULL, PRIBIO, "fdseek", hz);
+ retry_line = __LINE__;
+ if (fdc_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID)
+ return (1); /* XXX */
+ need_recal |= (1 << fd->fdsu);
+ if (fdin_rd(fdc) & FDI_DCHG) {
+ if (debugflags & 0x40)
+ printf("Empty in probe\n");
+ fd->flags |= FD_EMPTY;
+ } else {
+ if (debugflags & 0x40)
+ printf("Got disk in probe\n");
+ fd->flags &= ~FD_EMPTY;
+ retry_line = __LINE__;
+ if(fdc_sense_drive(fdc, &st3) != 0)
+ return (1);
+ if(st3 & NE7_ST3_WP)
+ fd->flags |= FD_WP;
+ else
+ fd->flags &= ~FD_WP;
+ }
+ return (fdc_biodone(fdc, 0));
+ }
+
+ /*
+ * If we are dead just flush the requests
+ */
+ if (fd->flags & FD_EMPTY)
+ return (fdc_biodone(fdc, ENXIO));
+
+ /* Check if we lost our media */
+ if (fdin_rd(fdc) & FDI_DCHG) {
+ if (debugflags & 0x40)
+ printf("Lost disk\n");
+ fd->flags |= FD_EMPTY;
+ fd->flags |= FD_NEWDISK;
+ g_topology_lock();
+ g_orphan_provider(fd->fd_provider, EXDEV);
+ fd->fd_provider->flags |= G_PF_WITHER;
+ fd->fd_provider =
+ g_new_providerf(fd->fd_geom, fd->fd_geom->name);
+ g_error_provider(fd->fd_provider, 0);
+ g_topology_unlock();
+ return (fdc_biodone(fdc, ENXIO));
+ }
+
+ /* Check if the floppy is write-protected */
+ if(bp->bio_cmd & (BIO_FMT | BIO_WRITE)) {
+ retry_line = __LINE__;
+ if(fdc_sense_drive(fdc, &st3) != 0)
+ return (1);
+ if(st3 & NE7_ST3_WP)
+ return (fdc_biodone(fdc, EROFS));
+ }
+
+ mfm = (fd->ft->flags & FL_MFM)? NE7CMD_MFM: 0;
+ steptrac = (fd->ft->flags & FL_2STEP)? 2: 1;
+ i = fd->ft->sectrac * fd->ft->heads;
+ cylinder = bp->bio_pblkno / i;
+ descyl = cylinder * steptrac;
+ sec = bp->bio_pblkno % i;
+ nsect = i - sec;
+ head = sec / fd->ft->sectrac;
+ sec = sec % fd->ft->sectrac + 1;
+
+ /* If everything is going swimmingly, use multisector xfer */
+ if (fdc->retry == 0 && bp->bio_cmd & (BIO_READ|BIO_WRITE)) {
+ fd->fd_iosize = imin(nsect * fd->sectorsize, bp->bio_resid);
+ nsect = fd->fd_iosize / fd->sectorsize;
+ } else if (bp->bio_cmd & (BIO_READ|BIO_WRITE)) {
+ fd->fd_iosize = fd->sectorsize;
+ nsect = 1;
+ }
+
+ /* Do RECAL if we need to or are going to track zero anyway */
+ if ((need_recal & (1 << fd->fdsu)) ||
+ (cylinder == 0 && fd->track != 0) ||
+ fdc->retry > 2) {
+ retry_line = __LINE__;
+ if (fdc_cmd(fdc, 2, NE7CMD_RECAL, fd->fdsu, 0))
+ return (1);
+ msleep(fdc, NULL, PRIBIO, "fdrecal", hz);
+ retry_line = __LINE__;
+ if (fdc_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID)
+ return (1); /* XXX */
+ retry_line = __LINE__;
+ if ((st0 & 0xc0) || cyl != 0)
+ return (1);
+ need_recal &= ~(1 << fd->fdsu);
+ fd->track = 0;
+ /* let the heads settle */
+ if (settle)
+ msleep(fdc->fd, NULL, PRIBIO, "fdhdstl", settle);
+ }
+
+ /*
+ * SEEK to where we want to be
+ *
+ * Enhanced controllers do implied seeks for read&write as long as
+ * we do not need multiple steps per track.
+ */
+ if (cylinder != fd->track && (
+ fdc->fdct != FDC_ENHANCED ||
+ descyl != cylinder ||
+ (bp->bio_cmd & (BIO_RDID|BIO_FMT)))) {
+ retry_line = __LINE__;
+ if (fdc_cmd(fdc, 3, NE7CMD_SEEK, fd->fdsu, descyl, 0))
+ return (1);
+ msleep(fdc, NULL, PRIBIO, "fdseek", hz);
+ retry_line = __LINE__;
+ if (fdc_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID)
+ return (1); /* XXX */
+ retry_line = __LINE__;
+ if ((st0 & 0xc0) || cyl != descyl) {
+ need_recal |= (1 << fd->fdsu);
+ return (1);
+ }
+ /* let the heads settle */
+ if (settle)
+ msleep(fdc->fd, NULL, PRIBIO, "fdhdstl", settle);
+ }
+ fd->track = cylinder;
+
+ if (debugflags & 8)
+ printf("op %x bn %ju siz %u ptr %p retry %d\n",
+ bp->bio_cmd, bp->bio_pblkno, fd->fd_iosize,
+ fd->fd_ioptr, fdc->retry);
+
+ /* Setup ISADMA if we need it and have it */
+ if ((bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_FMT))
+ && !(fdc->flags & FDC_NODMA)) {
+ mtx_lock(&Giant);
+ isa_dmastart(
+ bp->bio_cmd & BIO_READ ? ISADMA_READ : ISADMA_WRITE,
+ fd->fd_ioptr, fd->fd_iosize, fdc->dmachan);
+ mtx_unlock(&Giant);
+ fd->flags |= FD_ISADMA;
+ }
+
+ /* Do PIO if we have to */
+ if (fdc->flags & FDC_NODMA) {
+ if (bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_FMT))
+ SET_BCDR(fdc, 1, fd->fd_iosize, 0);
+ if (bp->bio_cmd & (BIO_WRITE|BIO_FMT))
+ fdc_pio(fdc);
+ }
+
+ switch(bp->bio_cmd) {
+ case BIO_FMT:
+ /* formatting */
+ finfo = (struct fd_formb *)bp->bio_data;
+ retry_line = __LINE__;
+ if (fdc_cmd(fdc, 6,
+ NE7CMD_FORMAT | mfm,
+ head << 2 | fd->fdsu,
+ finfo->fd_formb_secshift,
+ finfo->fd_formb_nsecs,
+ finfo->fd_formb_gaplen,
+ finfo->fd_formb_fillbyte, 0))
+ return (1);
+ break;
+ case BIO_RDID:
+ retry_line = __LINE__;
+ if (fdc_cmd(fdc, 2,
+ NE7CMD_READID | mfm,
+ head << 2 | fd->fdsu, 0))
+ return (1);
+ break;
+ case BIO_READ:
+ retry_line = __LINE__;
+ if (fdc_cmd(fdc, 9,
+ NE7CMD_READ | NE7CMD_SK | mfm | NE7CMD_MT,
+ head << 2 | fd->fdsu, /* head & unit */
+ fd->track, /* track */
+ head, /* head */
+ sec, /* sector + 1 */
+ fd->ft->secsize, /* sector size */
+ fd->ft->sectrac, /* sectors/track */
+ fd->ft->gap, /* gap size */
+ fd->ft->datalen, /* data length */
+ 0))
+ return (1);
+ break;
+ case BIO_WRITE:
+ retry_line = __LINE__;
+ if (fdc_cmd(fdc, 9,
+ NE7CMD_WRITE | mfm | NE7CMD_MT,
+ head << 2 | fd->fdsu, /* head & unit */
+ fd->track, /* track */
+ head, /* head */
+ sec, /* sector + 1 */
+ fd->ft->secsize, /* sector size */
+ fd->ft->sectrac, /* sectors/track */
+ fd->ft->gap, /* gap size */
+ fd->ft->datalen, /* data length */
+ 0))
+ return (1);
+ break;
+ default:
+ KASSERT(0 == 1, ("Wrong bio_cmd %x\n", bp->bio_cmd));
+ }
+
+ /* Wait for interrupt */
+ i = msleep(fdc, NULL, PRIBIO, "fddata", hz);
+
+ /* PIO if the read looks good */
+ if (i == 0 && (fdc->flags & FDC_NODMA) && (bp->bio_cmd & BIO_READ))
+ fdc_pio(fdc);
+
+ /* Finish DMA */
+ if (fd->flags & FD_ISADMA) {
+ mtx_lock(&Giant);
+ isa_dmadone(
+ bp->bio_cmd & BIO_READ ? ISADMA_READ : ISADMA_WRITE,
+ fd->fd_ioptr, fd->fd_iosize, fdc->dmachan);
+ mtx_unlock(&Giant);
+ fd->flags &= ~FD_ISADMA;
+ }
+
+ if (i != 0) {
+ /*
+ * Timeout.
+ *
+ * Due to IBM's brain-dead design, the FDC has a faked ready
+ * signal, hardwired to ready == true. Thus, any command
+ * issued if there's no diskette in the drive will _never_
+ * complete, and must be aborted by resetting the FDC.
+ * Many thanks, Big Blue!
+ */
+ retry_line = __LINE__;
+ fdc->flags |= FDC_NEEDS_RESET;
+ return (1);
+ }
+
+ retry_line = __LINE__;
+ if (fdc_read_status(fdc))
+ return (1);
+
+ if (debugflags & 0x10)
+ printf(" -> %x %x %x %x\n",
+ fdc->status[0], fdc->status[1],
+ fdc->status[2], fdc->status[3]);
+
+ st0 = fdc->status[0] & NE7_ST0_IC;
+ if (st0 != 0) {
+ retry_line = __LINE__;
+ if (st0 == NE7_ST0_IC_AT && fdc->status[1] & NE7_ST1_OR) {
+ /*
+ * DMA overrun. Someone hogged the bus and
+ * didn't release it in time for the next
+ * FDC transfer.
+ */
+ return (1);
+ }
+ retry_line = __LINE__;
+ if(st0 == NE7_ST0_IC_IV) {
+ fdc->flags |= FDC_NEEDS_RESET;
+ return (1);
+ }
+ retry_line = __LINE__;
+ if(st0 == NE7_ST0_IC_AT && fdc->status[2] & NE7_ST2_WC) {
+ need_recal |= (1 << fd->fdsu);
+ return (1);
+ }
+ if (debugflags & 0x20) {
+ printf("status %02x %02x %02x %02x %02x %02x\n",
+ fdc->status[0], fdc->status[1], fdc->status[2],
+ fdc->status[3], fdc->status[4], fdc->status[5]);
+ }
+ retry_line = __LINE__;
+ return (1);
+ }
+ /* All OK */
+ switch(bp->bio_cmd) {
+ case BIO_RDID:
+ /* copy out ID field contents */
+ idp = (struct fdc_readid *)bp->bio_data;
+ idp->cyl = fdc->status[3];
+ idp->head = fdc->status[4];
+ idp->sec = fdc->status[5];
+ idp->secshift = fdc->status[6];
+ if (debugflags & 0x40)
+ printf("c %d h %d s %d z %d\n",
+ idp->cyl, idp->head, idp->sec, idp->secshift);
+ break;
+ case BIO_READ:
+ case BIO_WRITE:
+ bp->bio_pblkno += nsect;
+ bp->bio_resid -= fd->fd_iosize;
+ bp->bio_completed += fd->fd_iosize;
+ fd->fd_ioptr += fd->fd_iosize;
+ /* Since we managed to get something done, reset the retry */
+ fdc->retry = 0;
+ if (bp->bio_resid > 0)
+ return (0);
+ break;
+ case BIO_FMT:
+ break;
+ }
+ return (fdc_biodone(fdc, 0));
+}
+
+static void
+fdc_thread(void *arg)
+{
+ struct fdc_data *fdc;
+
+ fdc = arg;
+ int i;
+
+ for (;;) {
+ i = fdc_worker(fdc);
+ if (i && debugflags & 0x20) {
+ if (fdc->bp != NULL) {
+ g_print_bio(fdc->bp);
+ printf("\n");
+ }
+ printf("Retry line %d\n", retry_line);
+ }
+ fdc->retry += i;
+ }
+}
+
+/*
+ * Enqueue a requst.
+ */
+static void
+fd_enqueue(struct fd_data *fd, struct bio *bp)
+{
+ struct fdc_data *fdc;
+ int call;
+
+ call = 0;
+ fdc = fd->fdc;
+ mtx_lock(&fdc->fdc_mtx);
+ /* If we go from idle, cancel motor turnoff */
+ if (fd->fd_iocount++ == 0)
+ callout_drain(&fd->toffhandle);
+ if (fd->flags & FD_MOTOR) {
+ /* The motor is on, send it directly to the controller */
+ bioq_disksort(&fdc->head, bp);
+ wakeup(&fdc->head);
+ } else {
+ /* Queue it on the drive until the motor has started */
+ bioq_insert_tail(&fd->fd_bq, bp);
+ if (!(fd->flags & FD_MOTORWAIT))
+ fd_motor(fd, 1);
+ }
+ mtx_unlock(&fdc->fdc_mtx);
+}
+
+static int
+fdmisccmd(struct fd_data *fd, u_int cmd, void *data)
+{
+ struct bio *bp;
+ struct fd_formb *finfo;
+ struct fdc_readid *idfield;
+ int error;
+
+ bp = malloc(sizeof(struct bio), M_TEMP, M_WAITOK | M_ZERO);
+
+ /*
+ * Set up a bio request for fdstrategy(). bio_offset is faked
+ * so that fdstrategy() will seek to the the requested
+ * cylinder, and use the desired head.
+ */
+ bp->bio_cmd = cmd;
+ if (cmd == BIO_FMT) {
+ finfo = (struct fd_formb *)data;
+ bp->bio_pblkno =
+ (finfo->cyl * fd->ft->heads + finfo->head) *
+ fd->ft->sectrac;
+ bp->bio_length = sizeof *finfo;
+ } else if (cmd == BIO_RDID) {
+ idfield = (struct fdc_readid *)data;
+ bp->bio_pblkno =
+ (idfield->cyl * fd->ft->heads + idfield->head) *
+ fd->ft->sectrac;
+ bp->bio_length = sizeof(struct fdc_readid);
+ } else if (cmd == BIO_PROBE) {
+ /* nothing */
+ } else
+ panic("wrong cmd in fdmisccmd()");
+ bp->bio_offset = bp->bio_pblkno * fd->sectorsize;
+ bp->bio_data = data;
+ bp->bio_driver1 = fd;
+ bp->bio_flags = 0;
+
+ fd_enqueue(fd, bp);
+
+ do {
+ msleep(bp, NULL, PRIBIO, "fdwait", hz);
+ } while (!(bp->bio_flags & BIO_DONE));
+ error = bp->bio_error;
+
+ free(bp, M_TEMP);
+ return (error);
+}
+
+/*
+ * Try figuring out the density of the media present in our device.
+ */
+static int
+fdautoselect(struct fd_data *fd)
+{
+ struct fd_type *fdtp;
+ struct fdc_readid id;
+ int oopts, rv;
+
+ if (!(fd->ft->flags & FL_AUTO))
+ return (0);
+
+ fdtp = fd_native_types[fd->type];
+ fdsettype(fd, fdtp);
+ if (!(fd->ft->flags & FL_AUTO))
+ return (0);
+
+ /*
+ * Try reading sector ID fields, first at cylinder 0, head 0,
+ * then at cylinder 2, head N. We don't probe cylinder 1,
+ * since for 5.25in DD media in a HD drive, there are no data
+ * to read (2 step pulses per media cylinder required). For
+ * two-sided media, the second probe always goes to head 1, so
+ * we can tell them apart from single-sided media. As a
+ * side-effect this means that single-sided media should be
+ * mentioned in the search list after two-sided media of an
+ * otherwise identical density. Media with a different number
+ * of sectors per track but otherwise identical parameters
+ * cannot be distinguished at all.
+ *
+ * If we successfully read an ID field on both cylinders where
+ * the recorded values match our expectation, we are done.
+ * Otherwise, we try the next density entry from the table.
+ *
+ * Stepping to cylinder 2 has the side-effect of clearing the
+ * unit attention bit.
+ */
+ oopts = fd->options;
+ fd->options |= FDOPT_NOERRLOG | FDOPT_NORETRY;
+ for (; fdtp->heads; fdtp++) {
+ fdsettype(fd, fdtp);
+
+ id.cyl = id.head = 0;
+ rv = fdmisccmd(fd, BIO_RDID, &id);
+ if (rv != 0)
+ continue;
+ if (id.cyl != 0 || id.head != 0 || id.secshift != fdtp->secsize)
+ continue;
+ id.cyl = 2;
+ id.head = fd->ft->heads - 1;
+ rv = fdmisccmd(fd, BIO_RDID, &id);
+ if (id.cyl != 2 || id.head != fdtp->heads - 1 ||
+ id.secshift != fdtp->secsize)
+ continue;
+ if (rv == 0)
+ break;
+ }
+
+ fd->options = oopts;
+ if (fdtp->heads == 0) {
+ if (debugflags & 0x40)
+ device_printf(fd->dev, "autoselection failed\n");
+ fdsettype(fd, fd_native_types[fd->type]);
+ return (0);
+ } else {
+ if (debugflags & 0x40) {
+ device_printf(fd->dev,
+ "autoselected %d KB medium\n", fd->ft->size / 2);
+ fdprinttype(fd->ft);
+ }
+ return (0);
+ }
+}
+
+/*
+ * GEOM class implementation
+ */
+
+static g_access_t fd_access;
+static g_start_t fd_start;
+static g_ioctl_t fd_ioctl;
+
+struct g_class g_fd_class = {
+ .name = "FD",
+ .version = G_VERSION,
+ .start = fd_start,
+ .access = fd_access,
+ .ioctl = fd_ioctl,
+};
+
+DECLARE_GEOM_CLASS(g_fd_class, g_fd);
+
+static int
+fd_access(struct g_provider *pp, int r, int w, int e)
+{
+ struct fd_data *fd;
+ struct fdc_data *fdc;
+ int ar, aw, ae;
+
+ fd = pp->geom->softc;
+ fdc = fd->fdc;
+
+ /*
+ * If our provider is withering, we can only get negative requests
+ * and we don't want to even see them
+ */
+ if (pp->flags & G_PF_WITHER)
+ return (0);
+
+ ar = r + pp->acr;
+ aw = w + pp->acw;
+ ae = e + pp->ace;
+
+ if (ar == 0 && aw == 0 && ae == 0) {
+ device_unbusy(fd->dev);
+ if (!(fdc->flags & FDC_NODMA) && --fdc->dmacnt == 0) {
+ mtx_lock(&Giant);
+ isa_dma_release(fdc->dmachan);
+ mtx_unlock(&Giant);
+ }
+ return (0);
+ }
+
+ if (pp->acr == 0 && pp->acw == 0 && pp->ace == 0) {
+ if (fdmisccmd(fd, BIO_PROBE, NULL))
+ return (ENXIO);
+ if (fd->flags & FD_EMPTY)
+ return (ENXIO);
+ if (fd->flags & FD_NEWDISK) {
+ fdautoselect(fd);
+ fd->flags &= ~FD_NEWDISK;
+ }
+ device_busy(fd->dev);
+ if (!(fdc->flags & FDC_NODMA) && fdc->dmacnt++ == 0) {
+ mtx_lock(&Giant);
+ isa_dma_acquire(fdc->dmachan);
+ isa_dmainit(fdc->dmachan, MAX_BYTES_PER_CYL);
+ mtx_unlock(&Giant);
+ }
+ }
+
+#ifdef notyet
+ if (w > 0 && (fd->flags & FD_WP))
+ return (EROFS);
+#endif
+
+ pp->sectorsize = fd->sectorsize;
+ pp->stripesize = fd->ft->heads * fd->ft->sectrac * fd->sectorsize;
+ pp->mediasize = pp->stripesize * fd->ft->tracks;
+ return (0);
+}
+
+static void
+fd_start(struct bio *bp)
+{
+ struct fdc_data * fdc;
+ struct fd_data * fd;
+
+ fd = bp->bio_to->geom->softc;
+ fdc = fd->fdc;
+ bp->bio_driver1 = fd;
+ if (bp->bio_cmd & BIO_GETATTR) {
+ if (g_handleattr_int(bp, "GEOM::fwsectors", fd->ft->sectrac))
+ return;
+ if (g_handleattr_int(bp, "GEOM::fwheads", fd->ft->heads))
+ return;
+ g_io_deliver(bp, ENOIOCTL);
+ return;
+ }
+ if (!(bp->bio_cmd & (BIO_READ|BIO_WRITE))) {
+ g_io_deliver(bp, EOPNOTSUPP);
+ return;
+ }
+ bp->bio_pblkno = bp->bio_offset / fd->sectorsize;
+ bp->bio_resid = bp->bio_length;
+ fd_enqueue(fd, bp);
+ return;
+}
+
+static int
+fd_ioctl(struct g_provider *pp, u_long cmd, void *data, struct thread *td)
+{
+ struct fd_data *fd;
+ struct fdc_status *fsp;
+ struct fdc_readid *rid;
+ int error;
+
+ fd = pp->geom->softc;
+
+ switch (cmd) {
+ case FD_GTYPE: /* get drive type */
+ *(struct fd_type *)data = *fd->ft;
+ return (0);
+
+ case FD_STYPE: /* set drive type */
+ /*
+ * Allow setting drive type temporarily iff
+ * currently unset. Used for fdformat so any
+ * user can set it, and then start formatting.
+ */
+ fd->fts = *(struct fd_type *)data;
+ if (fd->fts.sectrac) {
+ /* XXX: check for rubbish */
+ fdsettype(fd, &fd->fts);
+ } else {
+ fdsettype(fd, fd_native_types[fd->type]);
+ }
+ if (debugflags & 0x40)
+ fdprinttype(fd->ft);
+ return (0);
+
+ case FD_GOPTS: /* get drive options */
+ *(int *)data = fd->options;
+ return (0);
+
+ case FD_SOPTS: /* set drive options */
+ fd->options = *(int *)data;
+ return (0);
+
+ case FD_CLRERR:
+ if (suser(td) != 0)
+ return (EPERM);
+ fd->fdc->fdc_errs = 0;
+ return (0);
+
+ case FD_GSTAT:
+ fsp = (struct fdc_status *)data;
+ if ((fd->fdc->flags & FDC_STAT_VALID) == 0)
+ return (EINVAL);
+ memcpy(fsp->status, fd->fdc->status, 7 * sizeof(u_int));
+ return (0);
+
+ case FD_GDTYPE:
+ *(enum fd_drivetype *)data = fd->type;
+ return (0);
+
+ case FD_FORM:
+ if (((struct fd_formb *)data)->format_version !=
+ FD_FORMAT_VERSION)
+ return (EINVAL); /* wrong version of formatting prog */
+ error = fdmisccmd(fd, BIO_FMT, data);
+ fd->flags |= FD_NEWDISK;
+ break;
+
+ case FD_READID:
+ rid = (struct fdc_readid *)data;
+ if (rid->cyl > 85 || rid->head > 1)
+ return (EINVAL);
+ error = fdmisccmd(fd, BIO_RDID, data);
+ break;
+
+ case FIONBIO:
+ case FIOASYNC:
+ /* For backwards compat with old fd*(8) tools */
+ error = 0;
+ break;
+
+ default:
+ if (debugflags & 0x80)
+ printf("Unknown ioctl %lx\n", cmd);
+ error = ENOIOCTL;
+ break;
+ }
+ return (error);
+};
+
+
+
+/*
+ * Configuration/initialization stuff, per controller.
+ */
+
+devclass_t fdc_devclass;
+static devclass_t fd_devclass;
+
+struct fdc_ivars {
+ int fdunit;
+ int fdtype;
+};
+
void
fdc_release_resources(struct fdc_data *fdc)
{
@@ -547,10 +1519,6 @@ fdc_release_resources(struct fdc_data *fdc)
}
}
-/*
- * Configuration/initialization stuff, per controller.
- */
-
int
fdc_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
{
@@ -588,17 +1556,49 @@ fdc_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
}
int
-fdc_initial_reset(struct fdc_data *fdc)
+fdc_initial_reset(device_t dev, struct fdc_data *fdc)
{
+ int ic_type, part_id;
+
/* First, reset the floppy controller. */
fdout_wr(fdc, 0);
DELAY(100);
fdout_wr(fdc, FDO_FRST);
/* Then, see if it can handle a command. */
- if (fd_cmd(fdc, 3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240),
- NE7_SPEC_2(2, 0), 0))
+ if (fdc_cmd(fdc, 3, NE7CMD_SPECIFY, 0xaf, 0x1e, 0))
+ return (ENXIO);
+
+ /*
+ * Try to identify the chip.
+ *
+ * The i8272 datasheet documents that unknown commands
+ * will return ST0 as 0x80. The i8272 is supposedly identical
+ * to the NEC765.
+ * The i82077SL datasheet says 0x90 for the VERSION command,
+ * and several "superio" chips emulate this.
+ */
+ if (fdc_cmd(fdc, 1, NE7CMD_VERSION, 1, &ic_type))
+ return (ENXIO);
+ if (fdc_cmd(fdc, 1, 0x18, 1, &part_id))
return (ENXIO);
+ printf("ic_type %02x part_id %02x\n", ic_type, part_id);
+ switch (ic_type & 0xff) {
+ case 0x80:
+ device_set_desc(dev, "NEC 765 or clone");
+ fdc->fdct = FDC_NE765;
+ break;
+ case 0x81:
+ case 0x90:
+ device_set_desc(dev,
+ "Enhanced floppy controller");
+ fdc->fdct = FDC_ENHANCED;
+ break;
+ default:
+ device_set_desc(dev, "Generic floppy controller");
+ fdc->fdct = FDC_UNKNOWN;
+ break;
+ }
return (0);
}
@@ -614,10 +1614,12 @@ fdc_detach(device_t dev)
if ((error = bus_generic_detach(dev)))
return (error);
+ /* XXX: kill thread */
/* reset controller, turn motor off */
fdout_wr(fdc, 0);
fdc_release_resources(fdc);
+ mtx_destroy(&fdc->fdc_mtx);
return (0);
}
@@ -657,22 +1659,32 @@ fdc_attach(device_t dev)
fdc = device_get_softc(dev);
fdc->fdc_dev = dev;
+ error = fdc_initial_reset(dev, fdc);
+ if (error) {
+ device_printf(dev, "does not respond\n");
+ return (error);
+ }
error = BUS_SETUP_INTR(device_get_parent(dev), dev, fdc->res_irq,
- INTR_TYPE_BIO | INTR_ENTROPY, fdc_intr, fdc,
- &fdc->fdc_intr);
+ INTR_TYPE_BIO | INTR_ENTROPY | INTR_FAST | INTR_MPSAFE,
+ fdc_intr, fdc, &fdc->fdc_intr);
if (error) {
device_printf(dev, "cannot setup interrupt\n");
- return error;
+ return (error);
}
fdc->fdcu = device_get_unit(dev);
fdc->flags |= FDC_NEEDS_RESET;
- fdc->state = DEVIDLE;
+ mtx_init(&fdc->fdc_mtx, "fdc lock", NULL, MTX_DEF);
/* reset controller, turn motor off, clear fdout mirror reg */
fdout_wr(fdc, fdc->fdout = 0);
bioq_init(&fdc->head);
+ kthread_create(fdc_thread, fdc, &fdc->fdc_thread, 0, 0,
+ "fdc%d", device_get_unit(dev));
+
+ settle = hz / 8;
+
return (0);
}
@@ -709,7 +1721,7 @@ fdc_print_child(device_t me, device_t child)
if ((flags = device_get_flags(me)) != 0)
retval += printf(" flags %#x", flags);
retval += printf("\n");
-
+
return (retval);
}
@@ -719,11 +1731,11 @@ fdc_print_child(device_t me, device_t child)
static int
fd_probe(device_t dev)
{
- int i;
+ int i, unit;
u_int st0, st3;
struct fd_data *fd;
struct fdc_data *fdc;
- fdsu_t fdsu;
+ int fdsu;
int flags, type;
fdsu = fdc_get_fdunit(dev);
@@ -734,16 +1746,16 @@ fd_probe(device_t dev)
fd->dev = dev;
fd->fdc = fdc;
fd->fdsu = fdsu;
- fd->fdu = device_get_unit(dev);
+ unit = device_get_unit(dev);
/* Auto-probe if fdinfo is present, but always allow override. */
- type = FD_DTYPE(flags);
+ type = flags & FD_TYPEMASK;
if (type == FDT_NONE && (type = fdc_get_fdtype(dev)) != FDT_NONE) {
fd->type = type;
goto done;
} else {
/* make sure fdautoselect() will be called */
- fd->flags = FD_UA;
+ fd->flags = FD_EMPTY;
fd->type = type;
}
@@ -754,9 +1766,9 @@ fd_probe(device_t dev)
* == i386 breaks the test on FreeBSD/Alpha.
*/
#if defined(__i386__) || defined(__amd64__)
- if (fd->type == FDT_NONE && (fd->fdu == 0 || fd->fdu == 1)) {
+ if (fd->type == FDT_NONE && (unit == 0 || unit == 1)) {
/* Look up what the BIOS thinks we have. */
- if (fd->fdu == 0) {
+ if (unit == 0) {
if ((fdc->flags & FDC_ISPCMCIA))
/*
* Somewhat special. No need to force the
@@ -778,21 +1790,26 @@ fd_probe(device_t dev)
if (fd->type == FDT_NONE)
return (ENXIO);
+/*
+ mtx_lock(&fdc->fdc_mtx);
+*/
/* select it */
- set_motor(fdc, fdsu, TURNON);
+ fd_select(fd);
+ fd_motor(fd, 1);
+ fdc->fd = fd;
fdc_reset(fdc); /* XXX reset, then unreset, etc. */
DELAY(1000000); /* 1 sec */
if ((flags & FD_NO_PROBE) == 0) {
/* If we're at track 0 first seek inwards. */
- if ((fd_sense_drive_status(fdc, &st3) == 0) &&
+ if ((fdc_sense_drive(fdc, &st3) == 0) &&
(st3 & NE7_ST3_T0)) {
/* Seek some steps... */
- if (fd_cmd(fdc, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) {
+ if (fdc_cmd(fdc, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) {
/* ...wait a moment... */
DELAY(300000);
/* make ctrlr happy: */
- fd_sense_int(fdc, 0, 0);
+ fdc_sense_int(fdc, 0, 0);
}
}
@@ -804,33 +1821,29 @@ fd_probe(device_t dev)
* recalibrate more than 77 steps
*/
/* go back to 0: */
- if (fd_cmd(fdc, 2, NE7CMD_RECAL, fdsu, 0) == 0) {
+ if (fdc_cmd(fdc, 2, NE7CMD_RECAL, fdsu, 0) == 0) {
/* a second being enough for full stroke seek*/
DELAY(i == 0 ? 1000000 : 300000);
/* anything responding? */
- if (fd_sense_int(fdc, &st0, 0) == 0 &&
+ if (fdc_sense_int(fdc, &st0, 0) == 0 &&
(st0 & NE7_ST0_EC) == 0)
break; /* already probed succesfully */
}
}
}
- set_motor(fdc, fdsu, TURNOFF);
+ fd_motor(fd, 0);
+ fdc->fd = NULL;
+/*
+ mtx_unlock(&fdc->fdc_mtx);
+*/
if ((flags & FD_NO_PROBE) == 0 &&
(st0 & NE7_ST0_EC) != 0) /* no track 0 -> no drive present */
return (ENXIO);
done:
- /* This doesn't work before the first reset. */
- if ((fdc->flags & FDC_HAS_FIFO) == 0 &&
- fdc->fdct == FDC_ENHANCED &&
- (device_get_flags(fdc->fdc_dev) & FDC_NO_FIFO) == 0 &&
- enable_fifo(fdc) == 0) {
- device_printf(device_get_parent(dev),
- "FIFO enabled, %d bytes threshold\n", fifo_threshold);
- }
switch (fd->type) {
case FDT_12M:
@@ -855,29 +1868,44 @@ done:
fd->fdc = fdc;
fd->fdsu = fdsu;
fd->options = 0;
- callout_handle_init(&fd->toffhandle);
- callout_handle_init(&fd->tohandle);
+ callout_init(&fd->toffhandle, 1);
+ callout_init(&fd->tohandle, 1);
/* initialize densities for subdevices */
- for (i = 0; i < NUMDENS; i++)
- memcpy(fd->fts + i, fd_native_types + fd->type,
- sizeof(struct fd_type));
+ fdsettype(fd, fd_native_types[fd->type]);
return (0);
}
+/*
+ * We have to do this in a geom event because GEOM is not running
+ * when fd_attach() is.
+ * XXX: move fd_attach after geom like ata/scsi disks
+ */
+static void
+fd_attach2(void *arg, int flag)
+{
+ struct fd_data *fd;
+
+ fd = arg;
+
+ fd->fd_geom = g_new_geomf(&g_fd_class,
+ "fd%d", device_get_unit(fd->fdc->fdc_dev));
+ fd->fd_provider = g_new_providerf(fd->fd_geom, fd->fd_geom->name);
+ fd->fd_geom->softc = fd;
+ g_error_provider(fd->fd_provider, 0);
+}
+
static int
fd_attach(device_t dev)
{
struct fd_data *fd;
fd = device_get_softc(dev);
- fd->masterdev = make_dev(&fd_cdevsw, fd->fdu,
- UID_ROOT, GID_OPERATOR, 0640, "fd%d", fd->fdu);
- fd->masterdev->si_drv1 = fd;
- fd->device_stats = devstat_new_entry(device_get_name(dev),
- device_get_unit(dev), 0, DEVSTAT_NO_ORDERED_TAGS,
- DEVSTAT_TYPE_FLOPPY | DEVSTAT_TYPE_IF_OTHER,
- DEVSTAT_PRIORITY_FD);
+ g_post_event(fd_attach2, fd, M_WAITOK, NULL);
+ fd->flags |= FD_EMPTY;
+ bioq_init(&fd->fd_bq);
+ return (0);
+
return (0);
}
@@ -887,9 +1915,7 @@ fd_detach(device_t dev)
struct fd_data *fd;
fd = device_get_softc(dev);
- untimeout(fd_turnoff, fd, fd->toffhandle);
- devstat_remove_entry(fd->device_stats);
- destroy_dev(fd->masterdev);
+ callout_drain(&fd->toffhandle);
return (0);
}
@@ -902,7 +1928,6 @@ static device_method_t fd_methods[] = {
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend), /* XXX */
DEVMETHOD(device_resume, bus_generic_resume), /* XXX */
-
{ 0, 0 }
};
@@ -913,1414 +1938,3 @@ static driver_t fd_driver = {
};
DRIVER_MODULE(fd, fdc, fd_driver, fd_devclass, 0, 0);
-
-/*
- * More auxiliary functions.
- */
-/*
- * Motor control stuff.
- * Remember to not deselect the drive we're working on.
- */
-static void
-set_motor(struct fdc_data *fdc, int fdsu, int turnon)
-{
- int fdout;
-
- fdout = fdc->fdout;
- if (turnon) {
- fdout &= ~FDO_FDSEL;
- fdout |= (FDO_MOEN0 << fdsu) | FDO_FDMAEN | FDO_FRST | fdsu;
- } else
- fdout &= ~(FDO_MOEN0 << fdsu);
- fdc->fdout = fdout;
- fdout_wr(fdc, fdout);
- TRACE1("[0x%x->FDOUT]", fdout);
-}
-
-static void
-fd_turnoff(void *xfd)
-{
- int s;
- fd_p fd = xfd;
-
- TRACE1("[fd%d: turnoff]", fd->fdu);
-
- s = splbio();
- /*
- * Don't turn off the motor yet if the drive is active.
- *
- * If we got here, this could only mean we missed an interrupt.
- * This can e. g. happen on the Y-E Date PCMCIA floppy controller
- * after a controller reset. Just schedule a pseudo-interrupt
- * so the state machine gets re-entered.
- */
- if (fd->fdc->state != DEVIDLE && fd->fdc->fdu == fd->fdu) {
- fdc_intr(fd->fdc);
- splx(s);
- return;
- }
-
- fd->flags &= ~FD_MOTOR;
- set_motor(fd->fdc, fd->fdsu, TURNOFF);
- splx(s);
-}
-
-static void
-fd_motor_on(void *xfd)
-{
- int s;
- fd_p fd = xfd;
-
- s = splbio();
- fd->flags &= ~FD_MOTOR_WAIT;
- if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT))
- {
- fdc_intr(fd->fdc);
- }
- splx(s);
-}
-
-static void
-fd_turnon(fd_p fd)
-{
- if(!(fd->flags & FD_MOTOR))
- {
- fd->flags |= (FD_MOTOR + FD_MOTOR_WAIT);
- set_motor(fd->fdc, fd->fdsu, TURNON);
- timeout(fd_motor_on, fd, hz); /* in 1 sec its ok */
- }
-}
-
-static void
-fdc_reset(fdc_p fdc)
-{
- /* Try a reset, keep motor on */
- fdout_wr(fdc, fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
- TRACE1("[0x%x->FDOUT]", fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
- DELAY(100);
- /* enable FDC, but defer interrupts a moment */
- fdout_wr(fdc, fdc->fdout & ~FDO_FDMAEN);
- TRACE1("[0x%x->FDOUT]", fdc->fdout & ~FDO_FDMAEN);
- DELAY(100);
- fdout_wr(fdc, fdc->fdout);
- TRACE1("[0x%x->FDOUT]", fdc->fdout);
-
- /* XXX after a reset, silently believe the FDC will accept commands */
- (void)fd_cmd(fdc, 3, NE7CMD_SPECIFY,
- NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
- 0);
- if (fdc->flags & FDC_HAS_FIFO)
- (void) enable_fifo(fdc);
-}
-
-/*
- * FDC IO functions, take care of the main status register, timeout
- * in case the desired status bits are never set.
- *
- * These PIO loops initially start out with short delays between
- * each iteration in the expectation that the required condition
- * is usually met quickly, so it can be handled immediately. After
- * about 1 ms, stepping is increased to achieve a better timing
- * accuracy in the calls to DELAY().
- */
-static int
-fd_in(struct fdc_data *fdc, int *ptr)
-{
- int i, j, step;
-
- for (j = 0, step = 1;
- (i = fdsts_rd(fdc) & (NE7_DIO|NE7_RQM)) != (NE7_DIO|NE7_RQM) &&
- j < FDSTS_TIMEOUT;
- j += step) {
- if (i == NE7_RQM)
- return (fdc_err(fdc, "ready for output in input\n"));
- if (j == 1000)
- step = 1000;
- DELAY(step);
- }
- if (j >= FDSTS_TIMEOUT)
- return (fdc_err(fdc, bootverbose? "input ready timeout\n": 0));
-#ifdef FDC_DEBUG
- i = fddata_rd(fdc);
- TRACE1("[FDDATA->0x%x]", (unsigned char)i);
- *ptr = i;
- return (0);
-#else /* !FDC_DEBUG */
- i = fddata_rd(fdc);
- if (ptr)
- *ptr = i;
- return (0);
-#endif /* FDC_DEBUG */
-}
-
-static int
-out_fdc(struct fdc_data *fdc, int x)
-{
- int i, j, step;
-
- for (j = 0, step = 1;
- (i = fdsts_rd(fdc) & (NE7_DIO|NE7_RQM)) != NE7_RQM &&
- j < FDSTS_TIMEOUT;
- j += step) {
- if (i == (NE7_DIO|NE7_RQM))
- return (fdc_err(fdc, "ready for input in output\n"));
- if (j == 1000)
- step = 1000;
- DELAY(step);
- }
- if (j >= FDSTS_TIMEOUT)
- return (fdc_err(fdc, bootverbose? "output ready timeout\n": 0));
-
- /* Send the command and return */
- fddata_wr(fdc, x);
- TRACE1("[0x%x->FDDATA]", x);
- return (0);
-}
-
-/*
- * Block device driver interface functions (interspersed with even more
- * auxiliary functions).
- */
-static int
-fdopen(struct cdev *dev, int flags, int mode, struct thread *td)
-{
- fd_p fd;
- fdc_p fdc;
- int rv, unitattn, dflags;
-
- fd = dev->si_drv1;
- if (fd == NULL)
- return (ENXIO);
- fdc = fd->fdc;
- if ((fdc == NULL) || (fd->type == FDT_NONE))
- return (ENXIO);
- dflags = device_get_flags(fd->dev);
- /*
- * This is a bit bogus. It's still possible that e. g. a
- * descriptor gets inherited to a child, but then it's at
- * least for the same subdevice. By checking FD_OPEN here, we
- * can ensure that a device isn't attempted to be opened with
- * different densities at the same time where the second open
- * could clobber the settings from the first one.
- */
- if (fd->flags & FD_OPEN)
- return (EBUSY);
-
- if (flags & FNONBLOCK) {
- /*
- * Unfortunately, physio(9) discards its ioflag
- * argument, thus preventing us from seeing the
- * IO_NDELAY bit. So we need to keep track
- * ourselves.
- */
- fd->flags |= FD_NONBLOCK;
- fd->ft = 0;
- } else {
- /*
- * Figure out a unit attention condition.
- *
- * If UA has been forced, proceed.
- *
- * If the drive has no changeline support,
- * or if the drive parameters have been lost
- * due to previous non-blocking access,
- * assume a forced UA condition.
- *
- * If motor is off, turn it on for a moment
- * and select our drive, in order to read the
- * UA hardware signal.
- *
- * If motor is on, and our drive is currently
- * selected, just read the hardware bit.
- *
- * If motor is on, but active for another
- * drive on that controller, we are lost. We
- * cannot risk to deselect the other drive, so
- * we just assume a forced UA condition to be
- * on the safe side.
- */
- unitattn = 0;
- if ((dflags & FD_NO_CHLINE) != 0 ||
- (fd->flags & FD_UA) != 0 ||
- fd->ft == 0) {
- unitattn = 1;
- fd->flags &= ~FD_UA;
- } else if (fdc->fdout & (FDO_MOEN0 | FDO_MOEN1 |
- FDO_MOEN2 | FDO_MOEN3)) {
- if ((fdc->fdout & FDO_FDSEL) == fd->fdsu)
- unitattn = fdin_rd(fdc) & FDI_DCHG;
- else
- unitattn = 1;
- } else {
- set_motor(fdc, fd->fdsu, TURNON);
- unitattn = fdin_rd(fdc) & FDI_DCHG;
- set_motor(fdc, fd->fdsu, TURNOFF);
- }
- if (unitattn && (rv = fdautoselect(dev)) != 0)
- return (rv);
- }
- fd->flags |= FD_OPEN;
-
- if ((fdc->flags & FDC_NODMA) == 0) {
- if (fdc->dmacnt++ == 0) {
- isa_dma_acquire(fdc->dmachan);
- isa_dmainit(fdc->dmachan, MAX_SEC_SIZE);
- }
- }
-
- /*
- * Clearing the DMA overrun counter at open time is a bit messy.
- * Since we're only managing one counter per controller, opening
- * the second drive could mess it up. Anyway, if the DMA overrun
- * condition is really persistent, it will eventually time out
- * still. OTOH, clearing it here will ensure we'll at least start
- * trying again after a previous (maybe even long ago) failure.
- * Also, this is merely a stop-gap measure only that should not
- * happen during normal operation, so we can tolerate it to be a
- * bit sloppy about this.
- */
- fdc->dma_overruns = 0;
-
- return 0;
-}
-
-static int
-fdclose(struct cdev *dev, int flags, int mode, struct thread *td)
-{
- struct fd_data *fd;
- fdc_p fdc;
-
- fd = dev->si_drv1;
- fdc = fd->fdc;
- fd->flags &= ~(FD_OPEN | FD_NONBLOCK);
- fd->options &= ~(FDOPT_NORETRY | FDOPT_NOERRLOG | FDOPT_NOERROR);
-
- if ((fdc->flags & FDC_NODMA) == 0)
- if (--fdc->dmacnt == 0)
- isa_dma_release(fdc->dmachan);
-
- return (0);
-}
-
-static void
-fdstrategy(struct bio *bp)
-{
- long blknum, nblocks;
- int s;
- fdu_t fdu;
- fdc_p fdc;
- fd_p fd;
- size_t fdblk;
-
- fd = bp->bio_dev->si_drv1;
- fdu = fd->fdu;
- fdc = fd->fdc;
- bp->bio_resid = bp->bio_bcount;
- if (fd->type == FDT_NONE || fd->ft == 0) {
- if (fd->type != FDT_NONE && (fd->flags & FD_NONBLOCK))
- bp->bio_error = EAGAIN;
- else
- bp->bio_error = ENXIO;
- bp->bio_flags |= BIO_ERROR;
- goto bad;
- }
- fdblk = 128 << (fd->ft->secsize);
- if (bp->bio_cmd != FDBIO_FORMAT && bp->bio_cmd != FDBIO_RDSECTID) {
- if (fd->flags & FD_NONBLOCK) {
- bp->bio_error = EAGAIN;
- bp->bio_flags |= BIO_ERROR;
- goto bad;
- }
- if (bp->bio_offset < 0) {
- printf(
- "fd%d: fdstrat: bad request offset = %ju, bcount = %ld\n",
- fdu, (intmax_t)bp->bio_offset, bp->bio_bcount);
- bp->bio_error = EINVAL;
- bp->bio_flags |= BIO_ERROR;
- goto bad;
- }
- if ((bp->bio_bcount % fdblk) != 0) {
- bp->bio_error = EINVAL;
- bp->bio_flags |= BIO_ERROR;
- goto bad;
- }
- }
-
- /*
- * Set up block calculations.
- */
- if (bp->bio_offset >= ((off_t)128 << fd->ft->secsize) * fd->ft->size) {
- bp->bio_error = EINVAL;
- bp->bio_flags |= BIO_ERROR;
- goto bad;
- }
- blknum = bp->bio_offset / fdblk;
- nblocks = fd->ft->size;
- if (blknum + bp->bio_bcount / fdblk > nblocks) {
- if (blknum >= nblocks) {
- if (bp->bio_cmd != BIO_READ) {
- bp->bio_error = ENOSPC;
- bp->bio_flags |= BIO_ERROR;
- }
- goto bad; /* not always bad, but EOF */
- }
- bp->bio_bcount = (nblocks - blknum) * fdblk;
- }
- bp->bio_pblkno = blknum;
- s = splbio();
- bioq_disksort(&fdc->head, bp);
- untimeout(fd_turnoff, fd, fd->toffhandle); /* a good idea */
- devstat_start_transaction_bio(fd->device_stats, bp);
- device_busy(fd->dev);
- fdstart(fdc);
- splx(s);
- return;
-
-bad:
- biodone(bp);
-}
-
-/*
- * fdstart
- *
- * We have just queued something. If the controller is not busy
- * then simulate the case where it has just finished a command
- * So that it (the interrupt routine) looks on the queue for more
- * work to do and picks up what we just added.
- *
- * If the controller is already busy, we need do nothing, as it
- * will pick up our work when the present work completes.
- */
-static void
-fdstart(struct fdc_data *fdc)
-{
- int s;
-
- s = splbio();
- if(fdc->state == DEVIDLE)
- {
- fdc_intr(fdc);
- }
- splx(s);
-}
-
-static void
-fd_iotimeout(void *xfdc)
-{
- fdc_p fdc;
- int s;
-
- fdc = xfdc;
- TRACE1("fd%d[fd_iotimeout()]", fdc->fdu);
-
- /*
- * Due to IBM's brain-dead design, the FDC has a faked ready
- * signal, hardwired to ready == true. Thus, any command
- * issued if there's no diskette in the drive will _never_
- * complete, and must be aborted by resetting the FDC.
- * Many thanks, Big Blue!
- * The FDC must not be reset directly, since that would
- * interfere with the state machine. Instead, pretend that
- * the command completed but was invalid. The state machine
- * will reset the FDC and retry once.
- */
- s = splbio();
- fdc->status[0] = NE7_ST0_IC_IV;
- fdc->flags &= ~FDC_STAT_VALID;
- fdc->state = IOTIMEDOUT;
- fdc_intr(fdc);
- splx(s);
-}
-
-/* Just ensure it has the right spl. */
-static void
-fd_pseudointr(void *xfdc)
-{
- int s;
-
- s = splbio();
- fdc_intr(xfdc);
- splx(s);
-}
-
-/*
- * fdc_intr
- *
- * Keep calling the state machine until it returns a 0.
- * Always called at splbio.
- */
-static void
-fdc_intr(void *xfdc)
-{
- fdc_p fdc = xfdc;
- while(fdstate(fdc))
- ;
-}
-
-/*
- * Magic pseudo-DMA initialization for YE FDC. Sets count and
- * direction.
- */
-#define SET_BCDR(fdc,wr,cnt,port) \
- bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + port, \
- ((cnt)-1) & 0xff); \
- bus_space_write_1(fdc->portt, fdc->porth, fdc->port_off + port + 1, \
- ((wr ? 0x80 : 0) | ((((cnt)-1) >> 8) & 0x7f)));
-
-/*
- * fdcpio(): perform programmed IO read/write for YE PCMCIA floppy.
- */
-static int
-fdcpio(fdc_p fdc, long flags, caddr_t addr, u_int count)
-{
- u_char *cptr = (u_char *)addr;
-
- if (flags == BIO_READ) {
- if (fdc->state != PIOREAD) {
- fdc->state = PIOREAD;
- return(0);
- }
- SET_BCDR(fdc, 0, count, 0);
- bus_space_read_multi_1(fdc->portt, fdc->porth, fdc->port_off +
- FDC_YE_DATAPORT, cptr, count);
- } else {
- bus_space_write_multi_1(fdc->portt, fdc->porth, fdc->port_off +
- FDC_YE_DATAPORT, cptr, count);
- SET_BCDR(fdc, 0, count, 0);
- }
- return(1);
-}
-
-/*
- * Try figuring out the density of the media present in our device.
- */
-static int
-fdautoselect(struct cdev *dev)
-{
- fd_p fd;
- struct fd_type *fdtp;
- struct fdc_readid id;
- int i, n, oopts, rv;
-
- fd = dev->si_drv1;
-
- switch (fd->type) {
- default:
- return (ENXIO);
-
- case FDT_360K:
- case FDT_720K:
- /* no autoselection on those drives */
- fd->ft = fd_native_types + fd->type;
- return (0);
-
- case FDT_12M:
- fdtp = fd_searchlist_12m;
- n = sizeof fd_searchlist_12m / sizeof(struct fd_type);
- break;
-
- case FDT_144M:
- fdtp = fd_searchlist_144m;
- n = sizeof fd_searchlist_144m / sizeof(struct fd_type);
- break;
-
- case FDT_288M:
- fdtp = fd_searchlist_288m;
- n = sizeof fd_searchlist_288m / sizeof(struct fd_type);
- break;
- }
-
- /*
- * Try reading sector ID fields, first at cylinder 0, head 0,
- * then at cylinder 2, head N. We don't probe cylinder 1,
- * since for 5.25in DD media in a HD drive, there are no data
- * to read (2 step pulses per media cylinder required). For
- * two-sided media, the second probe always goes to head 1, so
- * we can tell them apart from single-sided media. As a
- * side-effect this means that single-sided media should be
- * mentioned in the search list after two-sided media of an
- * otherwise identical density. Media with a different number
- * of sectors per track but otherwise identical parameters
- * cannot be distinguished at all.
- *
- * If we successfully read an ID field on both cylinders where
- * the recorded values match our expectation, we are done.
- * Otherwise, we try the next density entry from the table.
- *
- * Stepping to cylinder 2 has the side-effect of clearing the
- * unit attention bit.
- */
- oopts = fd->options;
- fd->options |= FDOPT_NOERRLOG | FDOPT_NORETRY;
- for (i = 0; i < n; i++, fdtp++) {
- fd->ft = fdtp;
-
- id.cyl = id.head = 0;
- rv = fdmisccmd(dev, FDBIO_RDSECTID, &id);
- if (rv != 0)
- continue;
- if (id.cyl != 0 || id.head != 0 ||
- id.secshift != fdtp->secsize)
- continue;
- id.cyl = 2;
- id.head = fd->ft->heads - 1;
- rv = fdmisccmd(dev, FDBIO_RDSECTID, &id);
- if (id.cyl != 2 || id.head != fdtp->heads - 1 ||
- id.secshift != fdtp->secsize)
- continue;
- if (rv == 0)
- break;
- }
-
- fd->options = oopts;
- if (i == n) {
- if (bootverbose)
- device_printf(fd->dev, "autoselection failed\n");
- fd->ft = 0;
- return (EIO);
- } else {
- if (bootverbose)
- device_printf(fd->dev, "autoselected %d KB medium\n",
- fd->ft->size / 2);
- return (0);
- }
-}
-
-
-/*
- * The controller state machine.
- *
- * If it returns a non zero value, it should be called again immediately.
- */
-static int
-fdstate(fdc_p fdc)
-{
- struct fdc_readid *idp;
- int read, format, rdsectid, cylinder, head, i, sec = 0, sectrac;
- int st0, cyl, st3, idf, ne7cmd, mfm, steptrac;
- unsigned long blknum;
- fdu_t fdu = fdc->fdu;
- fd_p fd;
- register struct bio *bp;
- struct fd_formb *finfo = NULL;
- size_t fdblk;
-
- bp = fdc->bp;
- if (bp == NULL) {
- bp = bioq_first(&fdc->head);
- if (bp != NULL) {
- bioq_remove(&fdc->head, bp);
- fdc->bp = bp;
- }
- }
- if (bp == NULL) {
- /*
- * Nothing left for this controller to do,
- * force into the IDLE state.
- */
- fdc->state = DEVIDLE;
- if (fdc->fd) {
- device_printf(fdc->fdc_dev,
- "unexpected valid fd pointer\n");
- fdc->fd = (fd_p) 0;
- fdc->fdu = -1;
- }
- TRACE1("[fdc%d IDLE]", fdc->fdcu);
- return (0);
- }
- fd = bp->bio_dev->si_drv1;
- fdu = fd->fdu;
- fdblk = 128 << fd->ft->secsize;
- if (fdc->fd && (fd != fdc->fd))
- device_printf(fd->dev, "confused fd pointers\n");
- read = bp->bio_cmd == BIO_READ;
- mfm = (fd->ft->flags & FL_MFM)? NE7CMD_MFM: 0;
- steptrac = (fd->ft->flags & FL_2STEP)? 2: 1;
- if (read)
- idf = ISADMA_READ;
- else
- idf = ISADMA_WRITE;
- format = bp->bio_cmd == FDBIO_FORMAT;
- rdsectid = bp->bio_cmd == FDBIO_RDSECTID;
- if (format)
- finfo = (struct fd_formb *)bp->bio_data;
- TRACE1("fd%d", fdu);
- TRACE1("[%s]", fdstates[fdc->state]);
- TRACE1("(0x%x)", fd->flags);
- untimeout(fd_turnoff, fd, fd->toffhandle);
- fd->toffhandle = timeout(fd_turnoff, fd, 4 * hz);
- switch (fdc->state)
- {
- case DEVIDLE:
- case FINDWORK: /* we have found new work */
- fdc->retry = 0;
- fd->skip = 0;
- fdc->fd = fd;
- fdc->fdu = fdu;
- fdc->fdctl_wr(fdc, fd->ft->trans);
- TRACE1("[0x%x->FDCTL]", fd->ft->trans);
- /*
- * If the next drive has a motor startup pending, then
- * it will start up in its own good time.
- */
- if(fd->flags & FD_MOTOR_WAIT) {
- fdc->state = MOTORWAIT;
- return (0); /* will return later */
- }
- /*
- * Maybe if it's not starting, it SHOULD be starting.
- */
- if (!(fd->flags & FD_MOTOR))
- {
- fdc->state = MOTORWAIT;
- fd_turnon(fd);
- return (0); /* will return later */
- }
- else /* at least make sure we are selected */
- {
- set_motor(fdc, fd->fdsu, TURNON);
- }
- if (fdc->flags & FDC_NEEDS_RESET) {
- fdc->state = RESETCTLR;
- fdc->flags &= ~FDC_NEEDS_RESET;
- } else
- fdc->state = DOSEEK;
- return (1); /* will return immediately */
-
- case DOSEEK:
- blknum = bp->bio_pblkno + fd->skip / fdblk;
- cylinder = blknum / (fd->ft->sectrac * fd->ft->heads);
- if (cylinder == fd->track)
- {
- fdc->state = SEEKCOMPLETE;
- return (1); /* will return immediately */
- }
- if (fd_cmd(fdc, 3, NE7CMD_SEEK,
- fd->fdsu, cylinder * steptrac, 0))
- {
- /*
- * Seek command not accepted, looks like
- * the FDC went off to the Saints...
- */
- fdc->retry = 6; /* try a reset */
- return(retrier(fdc));
- }
- fd->track = FD_NO_TRACK;
- fdc->state = SEEKWAIT;
- return(0); /* will return later */
-
- case SEEKWAIT:
- /* allow heads to settle */
- timeout(fd_pseudointr, fdc, hz / 16);
- fdc->state = SEEKCOMPLETE;
- return(0); /* will return later */
-
- case SEEKCOMPLETE : /* seek done, start DMA */
- blknum = bp->bio_pblkno + fd->skip / fdblk;
- cylinder = blknum / (fd->ft->sectrac * fd->ft->heads);
-
- /* Make sure seek really happened. */
- if(fd->track == FD_NO_TRACK) {
- int descyl = cylinder * steptrac;
- do {
- /*
- * 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); /* will return later */
- 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
- */
- 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(fdc));
- }
- }
-
- if (cyl != descyl) {
- printf(
- "fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n",
- fdu, descyl, cyl, st0);
- if (fdc->retry < 3)
- fdc->retry = 3;
- return (retrier(fdc));
- }
- }
-
- fd->track = cylinder;
- if (format)
- fd->skip = (char *)&(finfo->fd_formb_cylno(0))
- - (char *)finfo;
- if (!rdsectid && !(fdc->flags & FDC_NODMA))
- isa_dmastart(idf, bp->bio_data+fd->skip,
- format ? bp->bio_bcount : fdblk, fdc->dmachan);
- blknum = bp->bio_pblkno + fd->skip / fdblk;
- sectrac = fd->ft->sectrac;
- sec = blknum % (sectrac * fd->ft->heads);
- head = sec / sectrac;
- sec = sec % sectrac + 1;
- if (head != 0 && fd->ft->offset_side2 != 0)
- sec += fd->ft->offset_side2;
- fd->hddrv = ((head&1)<<2)+fdu;
-
- if(format || !(read || rdsectid))
- {
- /* make sure the drive is writable */
- if(fd_sense_drive_status(fdc, &st3) != 0)
- {
- /* stuck controller? */
- if (!(fdc->flags & FDC_NODMA))
- isa_dmadone(idf,
- bp->bio_data + fd->skip,
- format ? bp->bio_bcount : fdblk,
- fdc->dmachan);
- fdc->retry = 6; /* reset the beast */
- return (retrier(fdc));
- }
- if(st3 & NE7_ST3_WP)
- {
- /*
- * XXX YES! this is ugly.
- * in order to force the current operation
- * to fail, we will have to fake an FDC
- * error - all error handling is done
- * by the retrier()
- */
- fdc->status[0] = NE7_ST0_IC_AT;
- fdc->status[1] = NE7_ST1_NW;
- fdc->status[2] = 0;
- fdc->status[3] = fd->track;
- fdc->status[4] = head;
- fdc->status[5] = sec;
- fdc->retry = 8; /* break out immediately */
- fdc->state = IOTIMEDOUT; /* not really... */
- return (1); /* will return immediately */
- }
- }
-
- if (format) {
- ne7cmd = NE7CMD_FORMAT | mfm;
- if (fdc->flags & FDC_NODMA) {
- /*
- * This seems to be necessary for
- * whatever obscure reason; if we omit
- * it, we end up filling the sector ID
- * fields of the newly formatted track
- * entirely with garbage, causing
- * `wrong cylinder' errors all over
- * the place when trying to read them
- * back.
- *
- * Umpf.
- */
- SET_BCDR(fdc, 1, bp->bio_bcount, 0);
-
- (void)fdcpio(fdc,bp->bio_cmd,
- bp->bio_data+fd->skip,
- bp->bio_bcount);
-
- }
- /* formatting */
- if(fd_cmd(fdc, 6, ne7cmd, head << 2 | fdu,
- finfo->fd_formb_secshift,
- finfo->fd_formb_nsecs,
- finfo->fd_formb_gaplen,
- finfo->fd_formb_fillbyte, 0)) {
- /* controller fell over */
- if (!(fdc->flags & FDC_NODMA))
- isa_dmadone(idf,
- bp->bio_data + fd->skip,
- format ? bp->bio_bcount : fdblk,
- fdc->dmachan);
- fdc->retry = 6;
- return (retrier(fdc));
- }
- } else if (rdsectid) {
- ne7cmd = NE7CMD_READID | mfm;
- if (fd_cmd(fdc, 2, ne7cmd, head << 2 | fdu, 0)) {
- /* controller jamming */
- fdc->retry = 6;
- return (retrier(fdc));
- }
- } else {
- /* read or write operation */
- ne7cmd = (read ? NE7CMD_READ | NE7CMD_SK : NE7CMD_WRITE) | mfm;
- if (fdc->flags & FDC_NODMA) {
- /*
- * This seems to be necessary even when
- * reading data.
- */
- SET_BCDR(fdc, 1, fdblk, 0);
-
- /*
- * Perform the write pseudo-DMA before
- * the WRITE command is sent.
- */
- if (!read)
- (void)fdcpio(fdc,bp->bio_cmd,
- bp->bio_data+fd->skip,
- fdblk);
- }
- if (fd_cmd(fdc, 9,
- ne7cmd,
- 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 */
- if (!(fdc->flags & FDC_NODMA))
- isa_dmadone(idf,
- bp->bio_data + fd->skip,
- format ? bp->bio_bcount : fdblk,
- fdc->dmachan);
- fdc->retry = 6;
- return (retrier(fdc));
- }
- }
- if (!rdsectid && (fdc->flags & FDC_NODMA))
- /*
- * If this is a read, then simply await interrupt
- * before performing PIO.
- */
- if (read && !fdcpio(fdc,bp->bio_cmd,
- bp->bio_data+fd->skip,fdblk)) {
- fd->tohandle = timeout(fd_iotimeout, fdc, hz);
- return(0); /* will return later */
- }
-
- /*
- * Write (or format) operation will fall through and
- * await completion interrupt.
- */
- fdc->state = IOCOMPLETE;
- fd->tohandle = timeout(fd_iotimeout, fdc, hz);
- return (0); /* will return later */
-
- case PIOREAD:
- /*
- * Actually perform the PIO read. The IOCOMPLETE case
- * removes the timeout for us.
- */
- (void)fdcpio(fdc,bp->bio_cmd,bp->bio_data+fd->skip,fdblk);
- fdc->state = IOCOMPLETE;
- /* FALLTHROUGH */
- case IOCOMPLETE: /* IO done, post-analyze */
- untimeout(fd_iotimeout, fdc, fd->tohandle);
-
- if (fd_read_status(fdc)) {
- if (!rdsectid && !(fdc->flags & FDC_NODMA))
- isa_dmadone(idf, bp->bio_data + fd->skip,
- format ? bp->bio_bcount : fdblk,
- fdc->dmachan);
- if (fdc->retry < 6)
- fdc->retry = 6; /* force a reset */
- return (retrier(fdc));
- }
-
- fdc->state = IOTIMEDOUT;
-
- /* FALLTHROUGH */
- case IOTIMEDOUT:
- if (!rdsectid && !(fdc->flags & FDC_NODMA))
- isa_dmadone(idf, bp->bio_data + fd->skip,
- format ? bp->bio_bcount : fdblk, fdc->dmachan);
- if (fdc->status[0] & NE7_ST0_IC) {
- if ((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT
- && fdc->status[1] & NE7_ST1_OR) {
- /*
- * DMA overrun. Someone hogged the bus and
- * didn't release it in time for the next
- * FDC transfer.
- *
- * We normally restart this without bumping
- * the retry counter. However, in case
- * something is seriously messed up (like
- * broken hardware), we rather limit the
- * number of retries so the IO operation
- * doesn't block indefinately.
- */
- if (fdc->dma_overruns++ < FDC_DMAOV_MAX) {
- fdc->state = SEEKCOMPLETE;
- return (1);/* will return immediately */
- } /* else fall through */
- }
- if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_IV
- && fdc->retry < 6)
- fdc->retry = 6; /* force a reset */
- else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT
- && fdc->status[2] & NE7_ST2_WC
- && fdc->retry < 3)
- fdc->retry = 3; /* force recalibrate */
- return (retrier(fdc));
- }
- /* All OK */
- if (rdsectid) {
- /* copy out ID field contents */
- idp = (struct fdc_readid *)bp->bio_data;
- idp->cyl = fdc->status[3];
- idp->head = fdc->status[4];
- idp->sec = fdc->status[5];
- idp->secshift = fdc->status[6];
- }
- /* Operation successful, retry DMA overruns again next time. */
- fdc->dma_overruns = 0;
- fd->skip += fdblk;
- if (!rdsectid && !format && fd->skip < bp->bio_bcount) {
- /* set up next transfer */
- fdc->state = DOSEEK;
- } else {
- /* ALL DONE */
- fd->skip = 0;
- bp->bio_resid = 0;
- fdc->bp = NULL;
- device_unbusy(fd->dev);
- biofinish(bp, fd->device_stats, 0);
- fdc->fd = (fd_p) 0;
- fdc->fdu = -1;
- fdc->state = FINDWORK;
- }
- return (1); /* will return immediately */
-
- case RESETCTLR:
- fdc_reset(fdc);
- fdc->retry++;
- fdc->state = RESETCOMPLETE;
- return (0); /* will return later */
-
- case RESETCOMPLETE:
- /*
- * Discard all the results from the reset so that they
- * can't cause an unexpected interrupt later.
- */
- for (i = 0; i < 4; i++)
- (void)fd_sense_int(fdc, &st0, &cyl);
- fdc->state = STARTRECAL;
- /* FALLTHROUGH */
- case STARTRECAL:
- if(fd_cmd(fdc, 2, NE7CMD_RECAL, fdu, 0)) {
- /* arrgl */
- fdc->retry = 6;
- return (retrier(fdc));
- }
- fdc->state = RECALWAIT;
- return (0); /* will return later */
-
- case RECALWAIT:
- /* allow heads to settle */
- timeout(fd_pseudointr, fdc, hz / 8);
- fdc->state = RECALCOMPLETE;
- return (0); /* will return later */
-
- case RECALCOMPLETE:
- do {
- /*
- * See SEEKCOMPLETE for a comment on this:
- */
- if (fd_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID)
- return (0); /* will return later */
- 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)
- {
- if(fdc->retry > 3)
- /*
- * A recalibrate from beyond cylinder 77
- * will "fail" due to the FDC limitations;
- * since people used to complain much about
- * the failure message, try not logging
- * this one if it seems to be the first
- * time in a line.
- */
- printf("fd%d: recal failed ST0 %b cyl %d\n",
- fdu, st0, NE7_ST0BITS, cyl);
- if(fdc->retry < 3) fdc->retry = 3;
- return (retrier(fdc));
- }
- fd->track = 0;
- /* Seek (probably) necessary */
- fdc->state = DOSEEK;
- return (1); /* will return immediately */
-
- case MOTORWAIT:
- if(fd->flags & FD_MOTOR_WAIT)
- {
- return (0); /* time's not up yet */
- }
- if (fdc->flags & FDC_NEEDS_RESET) {
- fdc->state = RESETCTLR;
- fdc->flags &= ~FDC_NEEDS_RESET;
- } else
- fdc->state = DOSEEK;
- return (1); /* will return immediately */
-
- default:
- device_printf(fdc->fdc_dev, "unexpected FD int->");
- if (fd_read_status(fdc) == 0)
- printf("FDC status :%x %x %x %x %x %x %x ",
- fdc->status[0],
- fdc->status[1],
- fdc->status[2],
- fdc->status[3],
- fdc->status[4],
- fdc->status[5],
- fdc->status[6] );
- else
- printf("No status available ");
- if (fd_sense_int(fdc, &st0, &cyl) != 0)
- {
- printf("[controller is dead now]\n");
- return (0); /* will return later */
- }
- printf("ST0 = %x, PCN = %x\n", st0, cyl);
- return (0); /* will return later */
- }
- /* noone should ever get here */
-}
-
-static int
-retrier(struct fdc_data *fdc)
-{
- struct bio *bp;
- struct fd_data *fd;
- int fdu;
-
- bp = fdc->bp;
-
- /* XXX shouldn't this be cached somewhere? */
- fd = bp->bio_dev->si_drv1;
- fdu = fd->fdu;
- if (fd->options & FDOPT_NORETRY)
- goto fail;
-
- switch (fdc->retry) {
- case 0: case 1: case 2:
- fdc->state = SEEKCOMPLETE;
- break;
- case 3: case 4: case 5:
- fdc->state = STARTRECAL;
- break;
- case 6:
- fdc->state = RESETCTLR;
- break;
- case 7:
- break;
- default:
- fail:
- if ((fd->options & FDOPT_NOERRLOG) == 0) {
- disk_err(bp, "hard error",
- fdc->fd->skip / DEV_BSIZE, 0);
- if (fdc->flags & FDC_STAT_VALID) {
- printf(
- " (ST0 %b ST1 %b ST2 %b cyl %u hd %u sec %u)\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");
- }
- if ((fd->options & FDOPT_NOERROR) == 0) {
- bp->bio_flags |= BIO_ERROR;
- bp->bio_error = EIO;
- bp->bio_resid = bp->bio_bcount - fdc->fd->skip;
- } else
- bp->bio_resid = 0;
- fdc->bp = NULL;
- fdc->fd->skip = 0;
- device_unbusy(fd->dev);
- biofinish(bp, fdc->fd->device_stats, 0);
- fdc->state = FINDWORK;
- fdc->flags |= FDC_NEEDS_RESET;
- fdc->fd = (fd_p) 0;
- fdc->fdu = -1;
- return (1);
- }
- fdc->retry++;
- return (1);
-}
-
-static void
-fdbiodone(struct bio *bp)
-{
- wakeup(bp);
-}
-
-static int
-fdmisccmd(struct cdev *dev, u_int cmd, void *data)
-{
- fdu_t fdu;
- fd_p fd;
- struct bio *bp;
- struct fd_formb *finfo;
- struct fdc_readid *idfield;
- size_t fdblk;
- int error;
-
- fd = dev->si_drv1;
- fdu = fd->fdu;
- fdblk = 128 << fd->ft->secsize;
- finfo = (struct fd_formb *)data;
- idfield = (struct fdc_readid *)data;
-
- bp = malloc(sizeof(struct bio), M_TEMP, M_WAITOK | M_ZERO);
-
- /*
- * Set up a bio request for fdstrategy(). bio_offset is faked
- * so that fdstrategy() will seek to the the requested
- * cylinder, and use the desired head.
- */
- bp->bio_cmd = cmd;
- if (cmd == FDBIO_FORMAT) {
- bp->bio_offset =
- (finfo->cyl * (fd->ft->sectrac * fd->ft->heads) +
- finfo->head * fd->ft->sectrac) * fdblk;
- bp->bio_bcount = sizeof(struct fd_idfield_data) *
- finfo->fd_formb_nsecs;
- } else if (cmd == FDBIO_RDSECTID) {
- bp->bio_offset =
- (idfield->cyl * (fd->ft->sectrac * fd->ft->heads) +
- idfield->head * fd->ft->sectrac) * fdblk;
- bp->bio_bcount = sizeof(struct fdc_readid);
- } else
- panic("wrong cmd in fdmisccmd()");
- bp->bio_data = data;
- bp->bio_dev = dev;
- bp->bio_done = fdbiodone;
- bp->bio_flags = 0;
-
- /* Now run the command. */
- fdstrategy(bp);
- error = biowait(bp, "fdcmd");
-
- free(bp, M_TEMP);
- return (error);
-}
-
-static int
-fdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
-{
- fdu_t fdu;
- fd_p fd;
- struct fdc_status *fsp;
- struct fdc_readid *rid;
- int error;
-
- fd = dev->si_drv1;
- fdu = fd->fdu;
-
- /*
- * First, handle everything that could be done with
- * FD_NONBLOCK still being set.
- */
- switch (cmd) {
-
- case DIOCGMEDIASIZE:
- if (fd->ft == 0)
- return ((fd->flags & FD_NONBLOCK) ? EAGAIN : ENXIO);
- *(off_t *)addr = (128 << (fd->ft->secsize)) * fd->ft->size;
- return (0);
-
- case DIOCGSECTORSIZE:
- if (fd->ft == 0)
- return ((fd->flags & FD_NONBLOCK) ? EAGAIN : ENXIO);
- *(u_int *)addr = 128 << (fd->ft->secsize);
- return (0);
-
- case FIONBIO:
- if (*(int *)addr != 0)
- fd->flags |= FD_NONBLOCK;
- else {
- if (fd->ft == 0) {
- /*
- * No drive type has been selected yet,
- * cannot turn FNONBLOCK off.
- */
- return (EINVAL);
- }
- fd->flags &= ~FD_NONBLOCK;
- }
- return (0);
-
- case FIOASYNC:
- /* keep the generic fcntl() code happy */
- return (0);
-
- case FD_GTYPE: /* get drive type */
- if (fd->ft == 0)
- /* no type known yet, return the native type */
- *(struct fd_type *)addr = fd_native_types[fd->type];
- else
- *(struct fd_type *)addr = *fd->ft;
- return (0);
-
- case FD_STYPE: /* set drive type */
- /*
- * Allow setting drive type temporarily iff
- * currently unset. Used for fdformat so any
- * user can set it, and then start formatting.
- */
- if (fd->ft)
- return (EINVAL); /* already set */
- fd->fts[0] = *(struct fd_type *)addr;
- fd->ft = &fd->fts[0];
- fd->flags |= FD_UA;
- return (0);
-
- case FD_GOPTS: /* get drive options */
- *(int *)addr = fd->options + FDOPT_AUTOSEL;
- return (0);
-
- case FD_SOPTS: /* set drive options */
- fd->options = *(int *)addr & ~FDOPT_AUTOSEL;
- return (0);
-
-#ifdef FDC_DEBUG
- case FD_DEBUG:
- if ((fd_debug != 0) != (*(int *)addr != 0)) {
- fd_debug = (*(int *)addr != 0);
- printf("fd%d: debugging turned %s\n",
- fd->fdu, fd_debug ? "on" : "off");
- }
- return (0);
-#endif
-
- case FD_CLRERR:
- if (suser(td) != 0)
- return (EPERM);
- fd->fdc->fdc_errs = 0;
- return (0);
-
- case FD_GSTAT:
- fsp = (struct fdc_status *)addr;
- if ((fd->fdc->flags & FDC_STAT_VALID) == 0)
- return (EINVAL);
- memcpy(fsp->status, fd->fdc->status, 7 * sizeof(u_int));
- return (0);
-
- case FD_GDTYPE:
- *(enum fd_drivetype *)addr = fd->type;
- return (0);
- }
-
- /*
- * Now handle everything else. Make sure we have a valid
- * drive type.
- */
- if (fd->flags & FD_NONBLOCK)
- return (EAGAIN);
- if (fd->ft == 0)
- return (ENXIO);
- error = 0;
-
- switch (cmd) {
-
- case FD_FORM:
- if ((flag & FWRITE) == 0)
- return (EBADF); /* must be opened for writing */
- if (((struct fd_formb *)addr)->format_version !=
- FD_FORMAT_VERSION)
- return (EINVAL); /* wrong version of formatting prog */
- error = fdmisccmd(dev, FDBIO_FORMAT, addr);
- break;
-
- case FD_GTYPE: /* get drive type */
- *(struct fd_type *)addr = *fd->ft;
- break;
-
- case FD_STYPE: /* set drive type */
- /* this is considered harmful; only allow for superuser */
- if (suser(td) != 0)
- return (EPERM);
- *fd->ft = *(struct fd_type *)addr;
- break;
-
- case FD_GOPTS: /* get drive options */
- *(int *)addr = fd->options;
- break;
-
- case FD_SOPTS: /* set drive options */
- fd->options = *(int *)addr;
- break;
-
-#ifdef FDC_DEBUG
- case FD_DEBUG:
- if ((fd_debug != 0) != (*(int *)addr != 0)) {
- fd_debug = (*(int *)addr != 0);
- printf("fd%d: debugging turned %s\n",
- fd->fdu, fd_debug ? "on" : "off");
- }
- break;
-#endif
-
- case FD_CLRERR:
- if (suser(td) != 0)
- return (EPERM);
- fd->fdc->fdc_errs = 0;
- break;
-
- case FD_GSTAT:
- fsp = (struct fdc_status *)addr;
- if ((fd->fdc->flags & FDC_STAT_VALID) == 0)
- return (EINVAL);
- memcpy(fsp->status, fd->fdc->status, 7 * sizeof(u_int));
- break;
-
- case FD_READID:
- rid = (struct fdc_readid *)addr;
- if (rid->cyl > MAX_CYLINDER || rid->head > MAX_HEAD)
- return (EINVAL);
- error = fdmisccmd(dev, FDBIO_RDSECTID, addr);
- break;
-
- default:
- error = ENOTTY;
- break;
- }
- return (error);
-}
diff --git a/sys/dev/fdc/fdc_acpi.c b/sys/dev/fdc/fdc_acpi.c
index 7b85500..af7bb62 100644
--- a/sys/dev/fdc/fdc_acpi.c
+++ b/sys/dev/fdc/fdc_acpi.c
@@ -37,7 +37,6 @@ __FBSDID("$FreeBSD$");
#include "acpi.h"
#include <dev/acpica/acpivar.h>
-#include <dev/fdc/fdcreg.h>
#include <dev/fdc/fdcvar.h>
static int fdc_acpi_probe(device_t dev);
@@ -46,7 +45,6 @@ static int fdc_acpi_probe_children(device_t bus, device_t dev,
void *fde);
static ACPI_STATUS fdc_acpi_probe_child(ACPI_HANDLE h, device_t *dev,
int level, void *arg);
-static void fdctl_wr_acpi(fdc_p fdc, u_int8_t v);
/* Maximum number of child devices of a controller (4 floppy + 1 tape.) */
#define ACPI_FDC_MAXDEVS 5
@@ -72,12 +70,6 @@ struct fdc_walk_ctx {
device_t dev;
};
-static void
-fdctl_wr_acpi(fdc_p fdc, u_int8_t v)
-{
- bus_space_write_1(fdc->ctlt, fdc->ctlh, 0, v);
-}
-
static int
fdc_acpi_probe(device_t dev)
{
@@ -101,7 +93,7 @@ fdc_acpi_attach(device_t dev)
struct fdc_data *sc;
ACPI_BUFFER buf;
device_t bus;
- int error, i, ic_type;
+ int error, i;
ACPI_OBJECT *obj, *pkg;
ACPI_HANDLE h;
uint32_t *fde;
@@ -109,7 +101,6 @@ fdc_acpi_attach(device_t dev)
/* Get our softc and use the same accessor as ISA. */
sc = device_get_softc(dev);
sc->fdc_dev = dev;
- sc->fdctl_wr = fdctl_wr_acpi;
sc->flags |= FDC_ISPNP;
/* Initialize variables and get a temporary buffer for _FDE. */
@@ -130,26 +121,6 @@ fdc_acpi_attach(device_t dev)
if (error != 0)
goto out;
- /* Check that the controller is working and get its type. */
- error = fdc_initial_reset(sc);
- if (error)
- goto out;
- if (fd_cmd(sc, 1, NE7CMD_VERSION, 1, &ic_type) == 0) {
- ic_type = (u_char)ic_type;
- switch (ic_type) {
- case 0x80:
- sc->fdct = FDC_NE765;
- break;
- case 0x81: /* not mentioned in any hardware doc */
- case 0x90:
- sc->fdct = FDC_ENHANCED;
- break;
- default:
- sc->fdct = FDC_UNKNOWN;
- break;
- }
- }
-
/*
* Enumerate _FDE, which lists floppy drives that are present. If
* this fails, fall back to the ISA hints-based probe method.
diff --git a/sys/dev/fdc/fdc_isa.c b/sys/dev/fdc/fdc_isa.c
index 5ca027e..c80dba0 100644
--- a/sys/dev/fdc/fdc_isa.c
+++ b/sys/dev/fdc/fdc_isa.c
@@ -33,20 +33,20 @@ __FBSDID("$FreeBSD$");
#include <sys/bio.h>
#include <sys/bus.h>
#include <sys/kernel.h>
+#include <sys/lock.h>
#include <sys/module.h>
+#include <sys/mutex.h>
#include <sys/rman.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <dev/fdc/fdcvar.h>
-#include <dev/fdc/fdcreg.h>
#include <isa/isavar.h>
#include <isa/isareg.h>
static int fdc_isa_probe(device_t);
-static void fdctl_wr_isa(fdc_p, u_int8_t);
static struct isa_pnp_id fdc_ids[] = {
{0x0007d041, "PC standard floppy disk controller"}, /* PNP0700 */
@@ -54,12 +54,6 @@ static struct isa_pnp_id fdc_ids[] = {
{0}
};
-static void
-fdctl_wr_isa(fdc_p fdc, u_int8_t v)
-{
- bus_space_write_1(fdc->ctlt, fdc->ctlh, 0, v);
-}
-
int
fdc_isa_alloc_resources(device_t dev, struct fdc_data *fdc)
{
@@ -165,6 +159,7 @@ fdc_isa_alloc_resources(device_t dev, struct fdc_data *fdc)
}
fdc->ctlt = rman_get_bustag(fdc->res_ctl);
fdc->ctlh = rman_get_bushandle(fdc->res_ctl);
+ fdc->ctl_off = 0;
fdc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &fdc->rid_irq,
RF_ACTIVE | RF_SHAREABLE);
@@ -189,12 +184,11 @@ fdc_isa_alloc_resources(device_t dev, struct fdc_data *fdc)
static int
fdc_isa_probe(device_t dev)
{
- int error, ic_type;
+ int error;
struct fdc_data *fdc;
fdc = device_get_softc(dev);
fdc->fdc_dev = dev;
- fdc->fdctl_wr = fdctl_wr_isa;
/* Check pnp ids */
error = ISA_PNP_PROBE(device_get_parent(dev), dev, fdc_ids);
@@ -203,32 +197,9 @@ fdc_isa_probe(device_t dev)
/* Attempt to allocate our resources for the duration of the probe */
error = fdc_isa_alloc_resources(dev, fdc);
- if (error)
- goto out;
-
- /* Check that the controller is working. */
- error = fdc_initial_reset(fdc);
- if (error)
- goto out;
-
- /* Try to determine a more specific device type. */
- if (fd_cmd(fdc, 1, NE7CMD_VERSION, 1, &ic_type) == 0) {
- switch (ic_type & 0xff) {
- case 0x80:
- device_set_desc(dev, "NEC 765 or clone");
- break;
- case 0x81: /* not mentioned in any hardware doc */
- case 0x90:
- device_set_desc(dev,
- "Enhanced floppy controller (i82077, NE72065 or clone)");
- break;
- default:
- device_set_desc(dev, "Generic floppy controller");
- break;
- }
- }
+ if (error == 0)
+ error = fdc_initial_reset(dev, fdc);
-out:
fdc_release_resources(fdc);
return (error);
}
@@ -236,40 +207,20 @@ out:
static int
fdc_isa_attach(device_t dev)
{
- int ic_type;
struct fdc_data *fdc;
int error;
fdc = device_get_softc(dev);
- fdc->fdctl_wr = fdctl_wr_isa;
error = ISA_PNP_PROBE(device_get_parent(dev), dev, fdc_ids);
if (error == 0)
fdc->flags |= FDC_ISPNP;
- if (fd_cmd(fdc, 1, NE7CMD_VERSION, 1, &ic_type) == 0) {
- switch (ic_type & 0xff) {
- case 0x80:
- fdc->fdct = FDC_NE765;
- break;
- case 0x81: /* not mentioned in any hardware doc */
- case 0x90:
- fdc->fdct = FDC_ENHANCED;
- break;
- default:
- fdc->fdct = FDC_UNKNOWN;
- break;
- }
- }
- error = fdc_isa_alloc_resources(dev, fdc);
- if (error)
- goto out;
- error = fdc_attach(dev);
- if (error)
- goto out;
- error = fdc_hints_probe(dev);
- if (error)
- goto out;
-out:
+ if (error == 0)
+ error = fdc_isa_alloc_resources(dev, fdc);
+ if (error == 0)
+ error = fdc_attach(dev);
+ if (error == 0)
+ error = fdc_hints_probe(dev);
if (error)
fdc_release_resources(fdc);
return (error);
diff --git a/sys/dev/fdc/fdc_pccard.c b/sys/dev/fdc/fdc_pccard.c
index 3dc5f25..c54d35a 100644
--- a/sys/dev/fdc/fdc_pccard.c
+++ b/sys/dev/fdc/fdc_pccard.c
@@ -33,7 +33,9 @@ __FBSDID("$FreeBSD$");
#include <sys/bio.h>
#include <sys/bus.h>
#include <sys/kernel.h>
+#include <sys/lock.h>
#include <sys/module.h>
+#include <sys/mutex.h>
#include <sys/rman.h>
#include <sys/systm.h>
#include <machine/bus.h>
@@ -41,11 +43,9 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <dev/fdc/fdcvar.h>
-#include <dev/fdc/fdcreg.h>
#include <dev/pccard/pccardvar.h>
#include "pccarddevs.h"
-static void fdctl_wr_pcmcia(fdc_p, u_int8_t);
static int fdc_pccard_probe(device_t);
static int fdc_pccard_attach(device_t);
@@ -53,12 +53,6 @@ static const struct pccard_product fdc_pccard_products[] = {
PCMCIA_CARD(YEDATA, EXTERNAL_FDD, 0),
};
-static void
-fdctl_wr_pcmcia(fdc_p fdc, u_int8_t v)
-{
- bus_space_write_1(fdc->portt, fdc->porth, FDCTL+fdc->port_off, v);
-}
-
static int
fdc_pccard_alloc_resources(device_t dev, struct fdc_data *fdc)
{
@@ -71,6 +65,9 @@ fdc_pccard_alloc_resources(device_t dev, struct fdc_data *fdc)
}
fdc->portt = rman_get_bustag(fdc->res_ioport);
fdc->porth = rman_get_bushandle(fdc->res_ioport);
+ fdc->ctlt = fdc->portt;
+ fdc->ctlh = fdc->porth;
+ fdc->ctl_off = 7;
fdc->rid_irq = 0;
fdc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &fdc->rid_irq,
@@ -105,17 +102,11 @@ fdc_pccard_attach(device_t dev)
return ENXIO;
fdc = device_get_softc(dev);
- fdc->fdctl_wr = fdctl_wr_pcmcia;
fdc->flags = FDC_NODMA;
fdc->fdct = FDC_NE765;
error = fdc_pccard_alloc_resources(dev, fdc);
- if (error)
- goto out;
- error = fdc_attach(dev);
- if (error)
- goto out;
-
-out:
+ if (error == 0)
+ error = fdc_attach(dev);
if (error)
fdc_release_resources(fdc);
return (error);
diff --git a/sys/dev/fdc/fdcvar.h b/sys/dev/fdc/fdcvar.h
index 3322575..22a4edd 100644
--- a/sys/dev/fdc/fdcvar.h
+++ b/sys/dev/fdc/fdcvar.h
@@ -30,71 +30,31 @@
/* XXX should audit this file to see if additional copyrights needed */
-enum fdc_type
-{
+enum fdc_type {
FDC_NE765, FDC_ENHANCED, FDC_UNKNOWN = -1
};
-enum fdc_states {
- DEVIDLE,
- FINDWORK,
- DOSEEK,
- SEEKCOMPLETE ,
- IOCOMPLETE,
- RECALCOMPLETE,
- STARTRECAL,
- RESETCTLR,
- SEEKWAIT,
- RECALWAIT,
- MOTORWAIT,
- IOTIMEDOUT,
- RESETCOMPLETE,
- PIOREAD
-};
-
-#ifdef FDC_DEBUG
-static char const * const fdstates[] = {
- "DEVIDLE",
- "FINDWORK",
- "DOSEEK",
- "SEEKCOMPLETE",
- "IOCOMPLETE",
- "RECALCOMPLETE",
- "STARTRECAL",
- "RESETCTLR",
- "SEEKWAIT",
- "RECALWAIT",
- "MOTORWAIT",
- "IOTIMEDOUT",
- "RESETCOMPLETE",
- "PIOREAD"
-};
-#endif
-
/*
* Per controller structure (softc).
*/
-struct fdc_data
-{
+struct fdc_data {
int fdcu; /* our unit number */
int dmacnt;
int dmachan;
int flags;
+#define FDC_HASDMA 0x01
#define FDC_STAT_VALID 0x08
#define FDC_HAS_FIFO 0x10
#define FDC_NEEDS_RESET 0x20
#define FDC_NODMA 0x40
#define FDC_ISPNP 0x80
#define FDC_ISPCMCIA 0x100
- struct fd_data *fd;
- int fdu; /* the active drive */
- enum fdc_states state;
+ struct fd_data *fd; /* The active drive */
int retry;
int fdout; /* mirror of the w/o digital output reg */
u_int status[7]; /* copy of the registers */
enum fdc_type fdct; /* chip version of FDC */
int fdc_errs; /* number of logged errors */
- int dma_overruns; /* number of DMA overruns */
struct bio_queue_head head;
struct bio *bp; /* active buffer */
struct resource *res_ioport, *res_ctl, *res_irq, *res_drq;
@@ -104,23 +64,13 @@ struct fdc_data
bus_space_handle_t porth;
bus_space_tag_t ctlt;
bus_space_handle_t ctlh;
+ int ctl_off;
void *fdc_intr;
struct device *fdc_dev;
- void (*fdctl_wr)(struct fdc_data *fdc, u_int8_t v);
+ struct mtx fdc_mtx;
+ struct proc *fdc_thread;
};
-typedef int fdu_t;
-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;
-
-/* error returns for fd_cmd() */
-#define FD_FAILED -1
-#define FD_NOT_VALID -2
-#define FDC_ERRMAX 100 /* do not log more */
-
extern devclass_t fdc_devclass;
enum fdc_device_ivars {
@@ -131,15 +81,12 @@ enum fdc_device_ivars {
__BUS_ACCESSOR(fdc, fdunit, FDC, FDUNIT, int);
__BUS_ACCESSOR(fdc, fdtype, FDC, FDTYPE, int);
-int fdc_alloc_resources(struct fdc_data *);
-void fdout_wr(fdc_p, u_int8_t);
-int fd_cmd(struct fdc_data *, int, ...);
void fdc_release_resources(struct fdc_data *);
int fdc_attach(device_t);
int fdc_hints_probe(device_t);
int fdc_detach(device_t dev);
device_t fdc_add_child(device_t, const char *, int);
-int fdc_initial_reset(struct fdc_data *);
+int fdc_initial_reset(device_t, struct fdc_data *);
int fdc_print_child(device_t, device_t);
int fdc_read_ivar(device_t, device_t, int, uintptr_t *);
int fdc_write_ivar(device_t, device_t, int, uintptr_t);
diff --git a/sys/sys/fdcio.h b/sys/sys/fdcio.h
index 48568ff..11e5e51 100644
--- a/sys/sys/fdcio.h
+++ b/sys/sys/fdcio.h
@@ -44,44 +44,41 @@ struct fd_formb {
int cyl, head;
int transfer_rate; /* FDC_???KBPS */
- union {
- struct fd_form_data {
+ struct fd_form_data {
+ /*
+ * DO NOT CHANGE THE LAYOUT OF THIS STRUCTS
+ * it is hardware-dependent since it exactly
+ * matches the byte sequence to write to FDC
+ * during its `format track' operation
+ */
+ u_char secshift; /* 0 -> 128, ...; usually 2 -> 512 */
+ u_char nsecs; /* must be <= FD_MAX_NSEC */
+ u_char gaplen; /* GAP 3 length; usually 84 */
+ u_char fillbyte; /* usually 0xf6 */
+ struct fd_idfield_data {
/*
- * DO NOT CHANGE THE LAYOUT OF THIS STRUCTS
- * it is hardware-dependent since it exactly
- * matches the byte sequence to write to FDC
- * during its `format track' operation
+ * data to write into id fields;
+ * for obscure formats, they mustn't match
+ * the real values (but mostly do)
*/
- u_char secshift; /* 0 -> 128, ...; usually 2 -> 512 */
- u_char nsecs; /* must be <= FD_MAX_NSEC */
- u_char gaplen; /* GAP 3 length; usually 84 */
- u_char fillbyte; /* usually 0xf6 */
- struct fd_idfield_data {
- /*
- * data to write into id fields;
- * for obscure formats, they mustn't match
- * the real values (but mostly do)
- */
- u_char cylno; /* 0 thru 79 (or 39) */
- u_char headno; /* 0, or 1 */
- u_char secno; /* starting at 1! */
- u_char secsize; /* usually 2 */
- } idfields[FD_MAX_NSEC]; /* 0 <= idx < nsecs used */
- } structured;
- u_char raw[1]; /* to have continuous indexed access */
+ u_char cylno; /* 0 thru 79 (or 39) */
+ u_char headno; /* 0, or 1 */
+ u_char secno; /* starting at 1! */
+ u_char secsize; /* usually 2 */
+ } idfields[FD_MAX_NSEC]; /* 0 <= idx < nsecs used */
} format_info;
};
/* make life easier */
-# define fd_formb_secshift format_info.structured.secshift
-# define fd_formb_nsecs format_info.structured.nsecs
-# define fd_formb_gaplen format_info.structured.gaplen
-# define fd_formb_fillbyte format_info.structured.fillbyte
+# define fd_formb_secshift format_info.secshift
+# define fd_formb_nsecs format_info.nsecs
+# define fd_formb_gaplen format_info.gaplen
+# define fd_formb_fillbyte format_info.fillbyte
/* these data must be filled in for(i = 0; i < fd_formb_nsecs; i++) */
-# define fd_formb_cylno(i) format_info.structured.idfields[i].cylno
-# define fd_formb_headno(i) format_info.structured.idfields[i].headno
-# define fd_formb_secno(i) format_info.structured.idfields[i].secno
-# define fd_formb_secsize(i) format_info.structured.idfields[i].secsize
+# define fd_formb_cylno(i) format_info.idfields[i].cylno
+# define fd_formb_headno(i) format_info.idfields[i].headno
+# define fd_formb_secno(i) format_info.idfields[i].secno
+# define fd_formb_secsize(i) format_info.idfields[i].secsize
struct fd_type {
int sectrac; /* sectors per track */
@@ -99,6 +96,7 @@ struct fd_type {
#define FL_MFM 0x0001 /* MFM recording */
#define FL_2STEP 0x0002 /* 2 steps between cylinders */
#define FL_PERPND 0x0004 /* perpendicular recording */
+#define FL_AUTO 0x0008 /* autodetect format */
};
struct fdc_status {
@@ -133,8 +131,6 @@ enum fd_drivetype {
#define FD_GOPTS _IOR('F', 64, int) /* drive options, see below */
#define FD_SOPTS _IOW('F', 65, int)
-#define FD_DEBUG _IOW('F', 66, int)
-
#define FD_CLRERR _IO('F', 67) /* clear error counter */
#define FD_READID _IOWR('F', 68, struct fdc_readid) /* read ID field */
@@ -152,8 +148,10 @@ enum fd_drivetype {
#define FDOPT_NOERRLOG 0x002 /* no "hard error" kernel log messages */
#define FDOPT_NOERROR 0x0004 /* do not indicate errors, caller will use
FD_GSTAT in order to obtain status */
+#ifdef PC98
#define FDOPT_AUTOSEL 0x8000 /* read/only option: device performs media
* autoselection */
+#endif
/*
* Transfer rate definitions. Used in the structures above. They
@@ -167,4 +165,34 @@ enum fd_drivetype {
#define FDC_250KBPS 0x02 /* 250KBPS MFM drive transfer rate */
#define FDC_1MBPS 0x03 /* 1MPBS MFM drive transfer rate */
+/*
+ * Parameters for common formats
+ *
+ * See struct fd_type for layout.
+ * XXX: Field 'size' must be calculated.
+ * XXX: Fields 'f_inter' and 'offset_side2' are unused by kernel.
+ *
+ * XXX: These should really go in a /etc/floppycap colon separated file
+ * XXX: but the kernel needs some of them for proper defaults and it would
+ * XXX: should have been done 20 years ago to make sense.
+ */
+#define FDF_3_2880 36,2,0xFF,0x1B,80,0,FDC_1MBPS,002,0x4C,1,1,FL_MFM|FL_PERPND
+#define FDF_3_1722 21,2,0xFF,0x04,82,0,FDC_500KBPS,2,0x0C,2,0,FL_MFM
+#define FDF_3_1476 18,2,0xFF,0x1B,82,0,FDC_500KBPS,2,0x6C,1,0,FL_MFM
+#define FDF_3_1440 18,2,0xFF,0x1B,80,0,FDC_500KBPS,2,0x6C,1,0,FL_MFM
+#define FDF_3_1200 15,2,0xFF,0x1B,80,0,FDC_500KBPS,2,0x54,1,0,FL_MFM
+#define FDF_3_820 10,2,0xFF,0x10,82,0,FDC_250KBPS,2,0x2e,1,0,FL_MFM
+#define FDF_3_800 10,2,0xFF,0x10,80,0,FDC_250KBPS,2,0x2e,1,0,FL_MFM
+#define FDF_3_720 9,2,0xFF,0x20,80,0,FDC_250KBPS,2,0x50,1,0,FL_MFM
+#define FDF_5_1480 18,2,0xFF,0x02,82,0,FDC_500KBPS,2,0x02,2,0,FL_MFM
+#define FDF_5_1440 18,2,0xFF,0x02,80,0,FDC_500KBPS,2,0x02,2,0,FL_MFM
+#define FDF_5_1230 8,3,0xFF,0x35,77,0,FDC_500KBPS,2,0x74,1,0,FL_MFM
+#define FDF_5_1200 15,2,0xFF,0x1B,80,0,FDC_500KBPS,2,0x54,1,0,FL_MFM
+#define FDF_5_820 10,2,0xFF,0x10,82,0,FDC_300KBPS,2,0x2e,1,0,FL_MFM
+#define FDF_5_800 10,2,0xFF,0x10,80,0,FDC_300KBPS,2,0x2e,1,0,FL_MFM
+#define FDF_5_720 9,2,0xFF,0x20,80,0,FDC_300KBPS,2,0x50,1,0,FL_MFM
+#define FDF_5_640 8,2,0xFF,0x2A,80,0,FDC_300KBPS,2,0x50,1,0,FL_MFM
+#define FDF_5_360 9,2,0xFF,0x23,40,0,FDC_300KBPS,2,0x50,1,0,FL_MFM
+/* XXX: 0x2a ? */
+
#endif /* !_MACHINE_IOCTL_FD_H_ */
diff --git a/usr.sbin/fdcontrol/fdcontrol.c b/usr.sbin/fdcontrol/fdcontrol.c
index 5ef5057..ff0f90b 100644
--- a/usr.sbin/fdcontrol/fdcontrol.c
+++ b/usr.sbin/fdcontrol/fdcontrol.c
@@ -41,7 +41,7 @@ __FBSDID("$FreeBSD$");
#include "fdutil.h"
-static int debug = -1, format, verbose, show = 1, showfmt;
+static int format, verbose, show = 1, showfmt;
static char *fmtstring;
static void showdev(enum fd_drivetype, const char *);
@@ -72,20 +72,14 @@ main(int argc, char **argv)
enum fd_drivetype type;
struct fd_type ft, newft, *fdtp;
const char *name, *descr;
- int fd, i, mode;
+ int fd, i, mode, autofmt;
- while((i = getopt(argc, argv, "d:Ff:s:v")) != -1)
+ autofmt = 0;
+ while((i = getopt(argc, argv, "aFf:s:v")) != -1)
switch(i) {
- case 'd':
- if (strcmp(optarg, "0") == 0)
- debug = 0;
- else if (strcmp(optarg, "1") == 0)
- debug = 1;
- else
- usage();
- show = 0;
- break;
+ case 'a':
+ autofmt = 1;
case 'F':
showfmt = 1;
show = 0;
@@ -141,6 +135,11 @@ mode = O_RDONLY | O_NONBLOCK;
return (0);
}
+ if (autofmt) {
+ memset(&newft, 0, sizeof newft);
+ ft = newft;
+ }
+
if (format) {
getname(type, &name, &descr);
fdtp = get_fmt(format, type);
@@ -195,6 +194,10 @@ mode = O_RDONLY | O_NONBLOCK;
printf("%sPERPENDICULAR", s);
s = ",";
}
+ if (ft.flags & FL_AUTO) {
+ printf("%sAUTO", s);
+ s = ",";
+ }
printf(">\n");
} else {
print_fmt(ft);
@@ -208,11 +211,5 @@ mode = O_RDONLY | O_NONBLOCK;
return (0);
}
- if (debug != -1) {
- if (ioctl(fd, FD_DEBUG, &debug) == -1)
- err(EX_OSERR, "ioctl(FD_DEBUG)");
- return (0);
- }
-
return 0;
}
diff --git a/usr.sbin/fdformat/fdformat.c b/usr.sbin/fdformat/fdformat.c
index dd92a86..8e29e40 100644
--- a/usr.sbin/fdformat/fdformat.c
+++ b/usr.sbin/fdformat/fdformat.c
@@ -268,13 +268,8 @@ main(int argc, char **argv)
parse_fmt(fmtstring, type, fdt, &newft);
fdt = newft;
}
- if (fdopts & FDOPT_AUTOSEL) {
- if (ioctl(fd, FD_STYPE, &fdt) < 0)
- err(EX_OSERR, "ioctl(FD_STYPE)");
- } else if (fmtstring || format) {
- errx(EX_USAGE,
- "-f fmt or -s fmtstr is only allowed for autoselecting devices");
- }
+ if (ioctl(fd, FD_STYPE, &fdt) < 0)
+ err(EX_OSERR, "ioctl(FD_STYPE)");
if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
err(EX_OSERR, "fcntl(F_GETFL)");
flags &= ~O_NONBLOCK;
diff --git a/usr.sbin/fdread/fdutil.c b/usr.sbin/fdread/fdutil.c
index 40f9daa..0b6c38f 100644
--- a/usr.sbin/fdread/fdutil.c
+++ b/usr.sbin/fdread/fdutil.c
@@ -59,7 +59,9 @@ printstatus(struct fdc_status *fdcsp, int terse)
fdcsp->status[5] & 0xff,
fdcsp->status[6] & 0xff);
- if ((fdcsp->status[0] & NE7_ST0_IC_RC) != NE7_ST0_IC_AT) {
+ if ((fdcsp->status[0] & NE7_ST0_IC_RC) == 0) {
+ sprintf(msgbuf, "timeout");
+ } else if ((fdcsp->status[0] & NE7_ST0_IC_RC) != NE7_ST0_IC_AT) {
sprintf(msgbuf, "unexcpted interrupt code %#x",
fdcsp->status[0] & NE7_ST0_IC_RC);
} else {
@@ -85,98 +87,60 @@ printstatus(struct fdc_status *fdcsp, int terse)
fputs(msgbuf, stderr);
}
-static struct fd_type fd_types_auto[1];
+static struct fd_type fd_types_auto[1] =
+ { { 0,0,0,0,0,0,0,0,0,0,0,FL_AUTO } };
-#ifdef PC98
-static struct fd_type fd_types_12m[] = {
-{ 15,2,0xFF,0x1B,80,2400,0,2,0x54,1,0,FL_MFM }, /* 1.2M */
-#if 0
-{ 10,2,0xFF,0x10,82,1640,1,2,0x30,1,0,FL_MFM }, /* 820K */
-{ 10,2,0xFF,0x10,80,1600,1,2,0x30,1,0,FL_MFM }, /* 800K */
-#endif
-{ 9,2,0xFF,0x20,80,1440,1,2,0x50,1,0,FL_MFM }, /* 720K */
-{ 9,2,0xFF,0x20,40, 720,1,2,0x50,1,0,FL_MFM|FL_2STEP },/* 360K */
-{ 8,2,0xFF,0x2A,80,1280,1,2,0x50,1,0,FL_MFM }, /* 640K */
-{ 8,3,0xFF,0x35,77,1232,0,2,0x74,1,0,FL_MFM }, /* 1.23M 1024/sec */
+static struct fd_type fd_types_288m[] = {
#if 0
-{ 8,3,0xFF,0x35,80,1280,0,2,0x74,1,0,FL_MFM }, /* 1.28M 1024/sec */
+ { FDF_3_2880 },
#endif
+ { FDF_3_1722 },
+ { FDF_3_1476 },
+ { FDF_3_1440 },
+ { FDF_3_1200 },
+ { FDF_3_820 },
+ { FDF_3_800 },
+ { FDF_3_720 },
+ { 0 }
};
static struct fd_type fd_types_144m[] = {
-#if 0
-{ 21,2,0xFF,0x04,82,3444,2,2,0x0C,2,0,FL_MFM }, /* 1.72M in 3mode */
-{ 18,2,0xFF,0x1B,82,2952,2,2,0x54,1,0,FL_MFM }, /* 1.48M in 3mode */
-#endif
-{ 18,2,0xFF,0x1B,80,2880,2,2,0x54,1,0,FL_MFM }, /* 1.44M in 3mode */
-{ 15,2,0xFF,0x1B,80,2400,0,2,0x54,1,0,FL_MFM }, /* 1.2M */
-#if 0
-{ 10,2,0xFF,0x10,82,1640,1,2,0x30,1,0,FL_MFM }, /* 820K */
-{ 10,2,0xFF,0x10,80,1600,1,2,0x30,1,0,FL_MFM }, /* 800K */
-#endif
-{ 9,2,0xFF,0x20,80,1440,1,2,0x50,1,0,FL_MFM }, /* 720K */
-{ 9,2,0xFF,0x20,40, 720,1,2,0x50,1,0,FL_MFM|FL_2STEP },/* 360K */
-{ 8,2,0xFF,0x2A,80,1280,1,2,0x50,1,0,FL_MFM }, /* 640K */
-{ 8,3,0xFF,0x35,77,1232,0,2,0x74,1,0,FL_MFM }, /* 1.23M 1024/sec */
-#if 0
-{ 8,3,0xFF,0x35,80,1280,0,2,0x74,1,0,FL_MFM }, /* 1.28M 1024/sec */
-{ 9,3,0xFF,0x35,82,1476,0,2,0x47,1,0,FL_MFM }, /* 1.48M 1024/sec 9sec */
-{ 10,3,0xFF,0x1B,82,1640,2,2,0x54,1,0,FL_MFM }, /* 1.64M in 3mode - Reserve */
-#endif
-};
-
-#else /* PC98 */
-
-static struct fd_type fd_types_288m[] =
-{
-#if 0
-{ 36,2,0xFF,0x1B,80,5760,FDC_1MBPS, 2,0x4C,1,1,FL_MFM|FL_PERPND } /*2.88M*/
-#endif
-{ 21,2,0xFF,0x04,82,3444,FDC_500KBPS,2,0x0C,2,0,FL_MFM }, /* 1.72M */
-{ 18,2,0xFF,0x1B,82,2952,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* 1.48M */
-{ 18,2,0xFF,0x1B,80,2880,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* 1.44M */
-{ 15,2,0xFF,0x1B,80,2400,FDC_500KBPS,2,0x54,1,0,FL_MFM }, /* 1.2M */
-{ 10,2,0xFF,0x10,82,1640,FDC_250KBPS,2,0x2E,1,0,FL_MFM }, /* 820K */
-{ 10,2,0xFF,0x10,80,1600,FDC_250KBPS,2,0x2E,1,0,FL_MFM }, /* 800K */
-{ 9,2,0xFF,0x20,80,1440,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* 720K */
+ { FDF_3_1722 },
+ { FDF_3_1476 },
+ { FDF_3_1440 },
+ { FDF_3_1200 },
+ { FDF_3_820 },
+ { FDF_3_800 },
+ { FDF_3_720 },
+ { 0 }
};
-static struct fd_type fd_types_144m[] =
-{
-{ 21,2,0xFF,0x04,82,3444,FDC_500KBPS,2,0x0C,2,0,FL_MFM }, /* 1.72M */
-{ 18,2,0xFF,0x1B,82,2952,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* 1.48M */
-{ 18,2,0xFF,0x1B,80,2880,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* 1.44M */
-{ 15,2,0xFF,0x1B,80,2400,FDC_500KBPS,2,0x54,1,0,FL_MFM }, /* 1.2M */
-{ 10,2,0xFF,0x10,82,1640,FDC_250KBPS,2,0x2E,1,0,FL_MFM }, /* 820K */
-{ 10,2,0xFF,0x10,80,1600,FDC_250KBPS,2,0x2E,1,0,FL_MFM }, /* 800K */
-{ 9,2,0xFF,0x20,80,1440,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* 720K */
-};
-
-static struct fd_type fd_types_12m[] =
-{
-{ 15,2,0xFF,0x1B,80,2400,FDC_500KBPS,2,0x54,1,0,FL_MFM }, /* 1.2M */
-{ 8,3,0xFF,0x35,77,1232,FDC_500KBPS,2,0x74,1,0,FL_MFM }, /* 1.23M */
-{ 18,2,0xFF,0x02,82,2952,FDC_500KBPS,2,0x02,2,0,FL_MFM }, /* 1.48M */
-{ 18,2,0xFF,0x02,80,2880,FDC_500KBPS,2,0x02,2,0,FL_MFM }, /* 1.44M */
-{ 10,2,0xFF,0x10,82,1640,FDC_300KBPS,2,0x2E,1,0,FL_MFM }, /* 820K */
-{ 10,2,0xFF,0x10,80,1600,FDC_300KBPS,2,0x2E,1,0,FL_MFM }, /* 800K */
-{ 9,2,0xFF,0x20,80,1440,FDC_300KBPS,2,0x50,1,0,FL_MFM }, /* 720K */
-{ 9,2,0xFF,0x23,40, 720,FDC_300KBPS,2,0x50,1,0,FL_MFM|FL_2STEP }, /* 360K */
-{ 8,2,0xFF,0x2A,80,1280,FDC_300KBPS,2,0x50,1,0,FL_MFM }, /* 640K */
+static struct fd_type fd_types_12m[] = {
+ { FDF_5_1200 },
+ { FDF_5_1230 },
+ { FDF_5_1480 },
+ { FDF_5_1440 },
+ { FDF_5_820 },
+ { FDF_5_800 },
+ { FDF_5_720 },
+ { FDF_5_360 | FL_2STEP },
+ { FDF_5_640 },
+ { 0 }
};
static struct fd_type fd_types_720k[] =
{
-{ 9,2,0xFF,0x20,80,1440,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* 720K */
+ { FDF_3_720 },
+ { 0 }
};
static struct fd_type fd_types_360k[] =
{
-{ 9,2,0xFF,0x2A,40, 720,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* 360K */
+ { FDF_5_360 },
+ { 0 }
};
-#endif /* PC98 */
/*
* Parse a format string, and fill in the parameter pointed to by `out'.
@@ -284,7 +248,6 @@ parse_fmt(const char *s, enum fd_drivetype type,
default:
abort(); /* paranoia */
-#ifndef PC98
case FDT_360K:
case FDT_720K:
if (j == 250)
@@ -292,23 +255,22 @@ parse_fmt(const char *s, enum fd_drivetype type,
else
errx(EX_USAGE, "bad speed %d", j);
break;
-#endif
case FDT_12M:
if (j == 300)
out->trans = FDC_300KBPS;
+ else if (j == 250)
+ out->trans = FDC_250KBPS;
else if (j == 500)
out->trans = FDC_500KBPS;
else
errx(EX_USAGE, "bad speed %d", j);
break;
-#ifndef PC98
case FDT_288M:
if (j == 1000)
out->trans = FDC_1MBPS;
/* FALLTHROUGH */
-#endif
case FDT_144M:
if (j == 250)
out->trans = FDC_250KBPS;
@@ -353,6 +315,10 @@ parse_fmt(const char *s, enum fd_drivetype type,
out->flags |= FL_MFM;
else if (strcmp(s1, "-mfm") == 0)
out->flags &= ~FL_MFM;
+ else if (strcmp(s1, "+auto") == 0)
+ out->flags |= FL_AUTO;
+ else if (strcmp(s1, "-auto") == 0)
+ out->flags &= ~FL_AUTO;
else if (strcmp(s1, "+2step") == 0)
out->flags |= FL_2STEP;
else if (strcmp(s1, "-2step") == 0)
@@ -399,6 +365,8 @@ print_fmt(struct fd_type in)
printf(",+2step");
if (in.flags & FL_PERPND)
printf(",+perpnd");
+ if (in.flags & FL_AUTO)
+ printf(",+auto");
putc('\n', stdout);
}
@@ -418,7 +386,6 @@ get_fmt(int size, enum fd_drivetype type)
default:
return (0);
-#ifndef PC98
case FDT_360K:
fdtp = fd_types_360k;
n = sizeof fd_types_360k / sizeof(struct fd_type);
@@ -428,7 +395,6 @@ get_fmt(int size, enum fd_drivetype type)
fdtp = fd_types_720k;
n = sizeof fd_types_720k / sizeof(struct fd_type);
break;
-#endif
case FDT_12M:
fdtp = fd_types_12m;
@@ -440,21 +406,20 @@ get_fmt(int size, enum fd_drivetype type)
n = sizeof fd_types_144m / sizeof(struct fd_type);
break;
-#ifndef PC98
case FDT_288M:
fdtp = fd_types_288m;
n = sizeof fd_types_288m / sizeof(struct fd_type);
break;
-#endif
}
if (size == -1)
return fd_types_auto;
- for (i = 0; i < n; i++, fdtp++)
+ for (i = 0; i < n; i++, fdtp++) {
+ fdtp->size = fdtp->sectrac * fdtp->heads * fdtp->tracks;
if (((128 << fdtp->secsize) * fdtp->size / 1024) == size)
return (fdtp);
-
+ }
return (0);
}
@@ -491,35 +456,29 @@ getname(enum fd_drivetype t, const char **name, const char **descr)
*descr = "unknown drive type";
break;
-#ifndef PC98
case FDT_360K:
*name = "360K";
*descr = "5.25\" double-density";
break;
-#endif
case FDT_12M:
*name = "1.2M";
*descr = "5.25\" high-density";
break;
-#ifndef PC98
case FDT_720K:
*name = "720K";
*descr = "3.5\" double-density";
break;
-#endif
case FDT_144M:
*name = "1.44M";
*descr = "3.5\" high-density";
break;
-#ifndef PC98
case FDT_288M:
*name = "2.88M";
*descr = "3.5\" extra-density";
break;
-#endif
}
}
OpenPOWER on IntegriCloud