summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authornyan <nyan@FreeBSD.org>2001-09-16 12:39:59 +0000
committernyan <nyan@FreeBSD.org>2001-09-16 12:39:59 +0000
commit71709394dd4daa743f21a4e2e446c58bd2aebe81 (patch)
treeb0dee9b8cc79d5b14a03bcddf0f8aea4cc67fd5a /sys
parentd7801d853b64e65a184efec07e768954568f17e4 (diff)
downloadFreeBSD-src-71709394dd4daa743f21a4e2e446c58bd2aebe81.zip
FreeBSD-src-71709394dd4daa743f21a4e2e446c58bd2aebe81.tar.gz
MFi386: sys/isa/fd.c revision from 1.205 to 1.219.
Diffstat (limited to 'sys')
-rw-r--r--sys/pc98/cbus/fdc.c963
-rw-r--r--sys/pc98/pc98/fd.c963
2 files changed, 1044 insertions, 882 deletions
diff --git a/sys/pc98/cbus/fdc.c b/sys/pc98/cbus/fdc.c
index bbf8b37..93eaf77 100644
--- a/sys/pc98/cbus/fdc.c
+++ b/sys/pc98/cbus/fdc.c
@@ -29,6 +29,13 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -44,7 +51,6 @@
*
* from: @(#)fd.c 7.4 (Berkeley) 5/25/91
* $FreeBSD$
- *
*/
#include "opt_fdc.h"
@@ -67,7 +73,6 @@
#include <sys/proc.h>
#include <sys/syslog.h>
-#include <sys/bus.h>
#include <machine/bus.h>
#include <sys/rman.h>
@@ -223,6 +228,13 @@ FDC_ACCESSOR(fdunit, FDUNIT, int)
#define FD_FAILED -1
#define FD_NOT_VALID -2
#define FDC_ERRMAX 100 /* do not log more */
+/*
+ * 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.
+ */
+#define FDC_DMAOV_MAX 25
#ifdef PC98
#define NUMTYPES 12
@@ -232,7 +244,7 @@ FDC_ACCESSOR(fdunit, FDUNIT, int)
#define NUMDENS (NUMTYPES - 7)
#endif
-#define NO_TYPE 0 /* must match NO_TYPE in ft.c */
+#define NO_TYPE 0
#define FD_1720 1
#define FD_1480 2
#define FD_1440 3
@@ -261,6 +273,7 @@ FDC_ACCESSOR(fdunit, FDUNIT, int)
#define FD_640in5_25 17
#endif
+#define BIO_RDSECTID BIO_CMD1
static struct fd_type fd_types[NUMTYPES] =
{
@@ -314,16 +327,15 @@ static bus_addr_t fdc_iat[] = {0, 2, 4};
#endif
#define MAX_SEC_SIZE (128 << 3)
+#define MAX_CYLINDER 85 /* some people really stress their drives
+ * up to cyl 82 */
+#define MAX_HEAD 1
-/***********************************************************************\
-* Per controller structure. *
-\***********************************************************************/
static devclass_t fdc_devclass;
-/***********************************************************************\
-* Per drive structure. *
-* N per controller (DRVS_PER_CTLR) *
-\***********************************************************************/
+/*
+ * Per drive structure (softc).
+ */
struct fd_data {
struct fdc_data *fdc; /* pointer to controller structure */
int fdsu; /* this units number on this controller */
@@ -339,12 +351,16 @@ struct fd_data {
#define FD_NO_TRACK -2
int track; /* where we think the head is */
int options; /* user configurable options, see ioctl_fd.h */
- struct callout_handle toffhandle;
- struct callout_handle tohandle;
- struct devstat device_stats;
#ifdef PC98
int pc98_trans;
#endif
+ struct callout_handle toffhandle;
+ struct callout_handle tohandle;
+ struct devstat device_stats;
+ eventhandler_tag clonetag;
+ dev_t masterdev;
+#define NCLONEDEVS 10 /* must match the table below */
+ dev_t clonedevs[NCLONEDEVS];
device_t dev;
fdu_t fdu;
};
@@ -404,17 +420,61 @@ nrd_info(addr)
}
#endif /* EPSON_NRDISK */
-/***********************************************************************\
-* 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) *
-\***********************************************************************/
-
-/* internal functions */
-static void fdc_intr(void *);
+/*
+ * 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)
+ */
+
+/*
+ * 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.
+ */
+#ifndef PC98
+static void fdout_wr(fdc_p, u_int8_t);
+#endif
+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);
+#ifndef PC98
+static void fdctl_wr_isa(fdc_p, u_int8_t);
+#if NCARD > 0
+static void fdctl_wr_pcmcia(fdc_p, u_int8_t);
+#endif
+#endif /* PC98 */
+#if 0
+static u_int8_t fdin_rd(fdc_p);
+#endif
+static int fdc_err(struct fdc_data *, const char *);
+static int fd_cmd(struct fdc_data *, int, ...);
+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 fdc_alloc_resources(struct fdc_data *);
+static void fdc_release_resources(struct fdc_data *);
+static int fdc_read_ivar(device_t, device_t, int, uintptr_t *);
+static int fdc_probe(device_t);
+#if NCARD > 0
+static int fdc_pccard_probe(device_t);
+#endif
+static int fdc_detach(device_t dev);
+static void fdc_add_child(device_t, const char *, int);
+static int fdc_attach(device_t);
+static int fdc_print_child(device_t, device_t);
+static void fd_clone (void *, char *, int, dev_t *);
+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
@@ -424,46 +484,39 @@ 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);
+/*
+ * The open function is named Fdopen() to avoid confusion with fdopen()
+ * in fd(4). The difference is now only meaningful for debuggers.
+ */
+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 fdstate(struct fdc_data *);
static int retrier(struct fdc_data *);
-static int fdformat(dev_t, struct fd_formb *, struct thread *);
-
-static int enable_fifo(fdc_p fdc);
-static void fd_clone (void *arg, char *name, int namelen, dev_t *dev);
+static void fdbiodone(struct bio *);
+static int fdmisccmd(dev_t, u_int, void *);
+static d_ioctl_t fdioctl;
static int fifo_threshold = 8; /* XXX: should be accessible via sysctl */
#ifdef FDC_DEBUG
-static char const * const fdstates[] =
-{
-"DEVIDLE",
-"FINDWORK",
-"DOSEEK",
-"SEEKCOMPLETE",
-"IOCOMPLETE",
-"RECALCOMPLETE",
-"STARTRECAL",
-"RESETCTLR",
-"SEEKWAIT",
-"RECALWAIT",
-"MOTORWAIT",
-"IOTIMEDOUT",
-"RESETCOMPLETE",
-"PIOREAD",
-};
-
/* CAUTION: fd_debug causes huge amounts of logging output */
static int volatile fd_debug = 0;
-#define TRACE0(arg) if(fd_debug) printf(arg)
-#define TRACE1(arg1, arg2) if(fd_debug) printf(arg1, arg2)
+#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)
-#define TRACE1(arg1, arg2)
+#define TRACE0(arg) do { } while (0)
+#define TRACE1(arg1, arg2) do { } while (0)
#endif /* FDC_DEBUG */
+/*
+ * Bus space handling (access to low-level IO).
+ */
#ifndef PC98
static void
fdout_wr(fdc_p fdc, u_int8_t v)
@@ -524,17 +577,7 @@ fdin_rd(fdc_p fdc)
#endif
-/*
- * named Fdopen() to avoid confusion with fdopen() in fd(4); the
- * difference is now only meaningful for debuggers
- */
-static d_open_t Fdopen;
-static d_close_t fdclose;
-static d_ioctl_t fdioctl;
-static d_strategy_t fdstrategy;
-
#define CDEV_MAJOR 9
-
static struct cdevsw fd_cdevsw = {
/* open */ Fdopen,
/* close */ fdclose,
@@ -551,6 +594,10 @@ static struct cdevsw fd_cdevsw = {
/* flags */ D_DISK,
};
+/*
+ * Auxiliary functions. Well, some only. Others are scattered
+ * throughout the entire file.
+ */
static int
fdc_err(struct fdc_data *fdc, const char *s)
{
@@ -712,13 +759,13 @@ fd_sense_int(fdc_p fdc, int *st0p, int *cylp)
static int
-fd_read_status(fdc_p fdc, int fdsu)
+fd_read_status(fdc_p fdc)
{
int i, ret;
- for (i = 0; i < 7; i++) {
+ for (i = ret = 0; i < 7; i++) {
/*
- * XXX types are poorly chosen. Only bytes can by read
+ * XXX types are poorly chosen. Only bytes can be read
* from the hardware, but fdc->status[] wants u_ints and
* fd_in() gives ints.
*/
@@ -757,9 +804,6 @@ fd_read_status(fdc_p fdc, int fdsu)
return ret;
}
-/****************************************************************************/
-/* autoconfiguration stuff */
-/****************************************************************************/
#ifdef PC98
static int pc98_trans = 0; /* 0 : HD , 1 : DD , 2 : 1.44 */
static int pc98_trans_prev = 0;
@@ -807,13 +851,17 @@ static int
fdc_alloc_resources(struct fdc_data *fdc)
{
device_t dev;
- int ispnp, ispcmcia;
#ifdef PC98
int rid;
+#else
+ int ispnp, ispcmcia, nports;
#endif
+
dev = fdc->fdc_dev;
+#ifndef PC98
ispnp = (fdc->flags & FDC_ISPNP) != 0;
ispcmcia = (fdc->flags & FDC_ISPCMCIA) != 0;
+#endif
fdc->rid_ioport = fdc->rid_irq = fdc->rid_drq = 0;
fdc->res_ioport = fdc->res_irq = fdc->res_drq = 0;
@@ -821,6 +869,11 @@ fdc_alloc_resources(struct fdc_data *fdc)
fdc->res_ioport = isa_alloc_resourcev(dev, SYS_RES_IOPORT,
&fdc->rid_ioport, fdc_iat,
3, RF_ACTIVE);
+ if (fdc->res_ioport == 0) {
+ device_printf(dev, "cannot reserve I/O port range\n");
+ return ENXIO;
+ }
+ isa_load_resourcev(fdc->res_ioport, fdc_iat, 3);
#else
/*
* On standard ISA, we don't just use an 8 port range
@@ -833,17 +886,15 @@ fdc_alloc_resources(struct fdc_data *fdc)
* uses the register with offset 6 for pseudo-DMA, and the
* one with offset 7 as control register.
*/
+ nports = ispcmcia ? 8 : (ispnp ? 1 : 6);
fdc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT,
&fdc->rid_ioport, 0ul, ~0ul,
- ispcmcia ? 8 : (ispnp ? 1 : 6),
- RF_ACTIVE);
-#endif
+ nports, RF_ACTIVE);
if (fdc->res_ioport == 0) {
- device_printf(dev, "cannot reserve I/O port range\n");
+ device_printf(dev, "cannot reserve I/O port range (%d ports)\n",
+ nports);
return ENXIO;
}
-#ifdef PC98
- isa_load_resourcev(fdc->res_ioport, fdc_iat, 3);
#endif
fdc->portt = rman_get_bustag(fdc->res_ioport);
fdc->porth = rman_get_bushandle(fdc->res_ioport);
@@ -911,7 +962,7 @@ fdc_alloc_resources(struct fdc_data *fdc)
0ul, ~0ul, 1, RF_ACTIVE);
if (fdc->res_ctl == 0) {
device_printf(dev,
- "cannot reserve control I/O port range\n");
+ "cannot reserve control I/O port range (control port)\n");
return ENXIO;
}
fdc->ctlt = rman_get_bustag(fdc->res_ctl);
@@ -987,9 +1038,9 @@ fdc_release_resources(struct fdc_data *fdc)
}
}
-/****************************************************************************/
-/* autoconfiguration stuff */
-/****************************************************************************/
+/*
+ * Configuration/initialization stuff, per controller.
+ */
static struct isa_pnp_id fdc_ids[] = {
{0x0007d041, "PC standard floppy disk controller"}, /* PNP0700 */
@@ -1012,9 +1063,6 @@ fdc_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
return 0;
}
-/*
- * fdc controller section.
- */
static int
fdc_probe(device_t dev)
{
@@ -1125,11 +1173,19 @@ fdc_pccard_probe(device_t dev)
#endif
/* see if it can handle a command */
+#ifdef PC98
+ if (fd_cmd(fdc, 3, NE7CMD_SPECIFY, NE7_SPEC_1(4, 240),
+ NE7_SPEC_2(2, 0), 0)) {
+ error = ENXIO;
+ goto out;
+ }
+#else
if (fd_cmd(fdc, 3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240),
NE7_SPEC_2(2, 0), 0)) {
error = ENXIO;
goto out;
}
+#endif
device_set_desc(dev, "Y-E Data PCMCIA floppy");
fdc->fdct = FDC_NE765;
@@ -1139,8 +1195,10 @@ out:
return (error);
}
+#endif /* NCARD > 0 */
+
static int
-fdc_pccard_detach(device_t dev)
+fdc_detach(device_t dev)
{
struct fdc_data *fdc;
int error;
@@ -1151,6 +1209,17 @@ fdc_pccard_detach(device_t dev)
if ((error = bus_generic_detach(dev)))
return (error);
+#ifdef PC98
+ /* reset controller, turn motor off */
+ fdc_reset(fdc);
+#else
+ /* reset controller, turn motor off */
+ fdout_wr(fdc, 0);
+#endif
+
+ if ((fdc->flags & FDC_NODMA) == 0)
+ isa_dma_release(fdc->dmachan);
+
if ((fdc->flags & FDC_ATTACHED) == 0) {
device_printf(dev, "already unloaded\n");
return (0);
@@ -1164,8 +1233,6 @@ fdc_pccard_detach(device_t dev)
return (0);
}
-#endif /* NCARD > 0 */
-
/*
* Add a child device to the fdc controller. It will then be probed etc.
*/
@@ -1194,8 +1261,8 @@ static int
fdc_attach(device_t dev)
{
struct fdc_data *fdc;
- int i, error, dunit;
const char *name, *dname;
+ int i, error, dunit;
fdc = device_get_softc(dev);
error = fdc_alloc_resources(fdc);
@@ -1211,7 +1278,7 @@ fdc_attach(device_t dev)
return error;
}
fdc->fdcu = device_get_unit(dev);
- fdc->flags |= FDC_ATTACHED;
+ fdc->flags |= FDC_ATTACHED | FDC_NEEDS_RESET;
if ((fdc->flags & FDC_NODMA) == 0) {
/*
@@ -1229,7 +1296,7 @@ fdc_attach(device_t dev)
fdc_reset(fdc);
#else
/* reset controller, turn motor off, clear fdout mirror reg */
- fdout_wr(fdc, ((fdc->fdout = 0)));
+ fdout_wr(fdc, fdc->fdout = 0);
#endif
bioq_init(&fdc->head);
@@ -1242,7 +1309,10 @@ fdc_attach(device_t dev)
while ((resource_find_match(&i, &dname, &dunit, "at", name)) == 0)
fdc_add_child(dev, dname, dunit);
- return (bus_generic_attach(dev));
+ if ((error = bus_generic_attach(dev)) != 0)
+ return (error);
+
+ return (0);
}
static int
@@ -1261,7 +1331,7 @@ static device_method_t fdc_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, fdc_probe),
DEVMETHOD(device_attach, fdc_attach),
- DEVMETHOD(device_detach, bus_generic_detach),
+ DEVMETHOD(device_detach, fdc_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),
DEVMETHOD(device_resume, bus_generic_resume),
@@ -1291,7 +1361,7 @@ static device_method_t fdc_pccard_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, fdc_pccard_probe),
DEVMETHOD(device_attach, fdc_attach),
- DEVMETHOD(device_detach, fdc_pccard_detach),
+ DEVMETHOD(device_detach, fdc_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),
DEVMETHOD(device_resume, bus_generic_resume),
@@ -1319,14 +1389,10 @@ static struct {
int minor;
int link;
} fd_suffix[] = {
- { "a", 0, 1 },
- { "b", 0, 1 },
- { "c", 0, 1 },
- { "d", 0, 1 },
- { "e", 0, 1 },
- { "f", 0, 1 },
- { "g", 0, 1 },
- { "h", 0, 1 },
+ /*
+ * Genuine clone devices must come first, and their number must
+ * match NCLONEDEVS above.
+ */
{ ".1720", 1, 0 },
{ ".1480", 2, 0 },
{ ".1440", 3, 0 },
@@ -1341,15 +1407,25 @@ static struct {
{ ".1280", 11, 0 },
{ ".1476", 12, 0 },
#endif
+ { "a", 0, 1 },
+ { "b", 0, 1 },
+ { "c", 0, 1 },
+ { "d", 0, 1 },
+ { "e", 0, 1 },
+ { "f", 0, 1 },
+ { "g", 0, 1 },
+ { "h", 0, 1 },
{ 0, 0 }
};
+
static void
-fd_clone (void *arg, char *name, int namelen, dev_t *dev)
+fd_clone(void *arg, char *name, int namelen, dev_t *dev)
{
+ struct fd_data *fd;
int u, d, i;
char *n;
- dev_t pdev;
+ fd = (struct fd_data *)arg;
if (*dev != NODEV)
return;
if (dev_stdclone(name, &n, "fd", &u) != 2)
@@ -1365,15 +1441,14 @@ fd_clone (void *arg, char *name, int namelen, dev_t *dev)
if (fd_suffix[i].link == 0) {
*dev = make_dev(&fd_cdevsw, (u << 6) + d,
UID_ROOT, GID_OPERATOR, 0640, name);
+ fd->clonedevs[i] = *dev;
} else {
- pdev = makedev(fd_cdevsw.d_maj, (u << 6) + d);
- *dev = make_dev_alias(pdev, name);
+ *dev = make_dev_alias(fd->masterdev, name);
}
}
-/******************************************************************/
/*
- * devices attached to the controller section.
+ * Configuration/initialization, per drive.
*/
static int
fd_probe(device_t dev)
@@ -1475,6 +1550,7 @@ fd_probe(device_t dev)
#ifndef PC98
/* select it */
set_motor(fdc, fdsu, TURNON);
+ fdc_reset(fdc); /* XXX reset, then unreset, etc. */
DELAY(1000000); /* 1 sec */
/* XXX This doesn't work before the first set_motor() */
@@ -1607,21 +1683,19 @@ static int
fd_attach(device_t dev)
{
struct fd_data *fd;
- static int cdevsw_add_done = 0;
-
- fd = device_get_softc(dev);
+ static int cdevsw_add_done;
+ int i;
if (!cdevsw_add_done) {
cdevsw_add(&fd_cdevsw); /* XXX */
- cdevsw_add_done++;
+ cdevsw_add_done = 1;
}
- EVENTHANDLER_REGISTER(dev_clone, fd_clone, 0, 1000);
- make_dev(&fd_cdevsw, (fd->fdu << 6),
- UID_ROOT, GID_OPERATOR, 0640, "fd%d", fd->fdu);
-
- /*
- * Export the drive to the devstat interface.
- */
+ fd = device_get_softc(dev);
+ fd->clonetag = EVENTHANDLER_REGISTER(dev_clone, fd_clone, fd, 1000);
+ fd->masterdev = make_dev(&fd_cdevsw, fd->fdu << 6,
+ UID_ROOT, GID_OPERATOR, 0640, "fd%d", fd->fdu);
+ for (i = 0; i < NCLONEDEVS; i++)
+ fd->clonedevs[i] = NODEV;
devstat_add_entry(&fd->device_stats, device_get_name(dev),
device_get_unit(dev), 0, DEVSTAT_NO_ORDERED_TAGS,
DEVSTAT_TYPE_FLOPPY | DEVSTAT_TYPE_IF_OTHER,
@@ -1633,9 +1707,17 @@ static int
fd_detach(device_t dev)
{
struct fd_data *fd;
+ int i;
fd = device_get_softc(dev);
untimeout(fd_turnoff, fd, fd->toffhandle);
+ devstat_remove_entry(&fd->device_stats);
+ destroy_dev(fd->masterdev);
+ for (i = 0; i < NCLONEDEVS; i++)
+ if (fd->clonedevs[i] != NODEV)
+ destroy_dev(fd->clonedevs[i]);
+ cdevsw_remove(&fd_cdevsw);
+ EVENTHANDLER_DEREGISTER(dev_clone, fd->clonetag);
return (0);
}
@@ -1660,10 +1742,13 @@ static driver_t fd_driver = {
DRIVER_MODULE(fd, fdc, fd_driver, fd_devclass, 0, 0);
-/****************************************************************************/
-/* motor control stuff */
-/* remember to not deselect the drive we're working on */
-/****************************************************************************/
+/*
+ * 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)
{
@@ -1673,51 +1758,17 @@ set_motor(struct fdc_data *fdc, int fdsu, int turnon)
DELAY(10);
fdctl_wr(fdc, FDC_DMAE | FDC_MTON);
#else
- int fdout = fdc->fdout;
- int needspecify = 0;
+ int fdout;
- if(turnon) {
+ fdout = fdc->fdout;
+ if (turnon) {
fdout &= ~FDO_FDSEL;
- fdout |= (FDO_MOEN0 << fdsu) + fdsu;
+ fdout |= (FDO_MOEN0 << fdsu) | FDO_FDMAEN | FDO_FRST | fdsu;
} else
fdout &= ~(FDO_MOEN0 << fdsu);
-
- if(!turnon
- && (fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0)
- /* gonna turn off the last drive, put FDC to bed */
- fdout &= ~ (FDO_FRST|FDO_FDMAEN);
- else {
- /* make sure controller is selected and specified */
- if((fdout & (FDO_FRST|FDO_FDMAEN)) == 0)
- needspecify = 1;
- fdout |= (FDO_FRST|FDO_FDMAEN);
- }
-
- fdout_wr(fdc, fdout);
fdc->fdout = fdout;
+ fdout_wr(fdc, fdout);
TRACE1("[0x%x->FDOUT]", fdout);
-
- if (needspecify) {
- /*
- * we silently assume the command will be accepted
- * after an FDC reset
- *
- * Steinbach's Guideline for Systems Programming:
- * Never test for an error condition you don't know
- * how to handle.
- */
-#ifdef PC98
- (void)fd_cmd(fdc, 3, NE7CMD_SPECIFY,
- NE7_SPEC_1(4, 240), NE7_SPEC_2(2, 0),
- 0);
-#else
- (void)fd_cmd(fdc, 3, NE7CMD_SPECIFY,
- NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
- 0);
-#endif
- if (fdc->flags & FDC_HAS_FIFO)
- (void) enable_fifo(fdc);
- }
#endif
}
@@ -1800,7 +1851,7 @@ fdc_reset(fdc_p fdc)
TRACE1("[0x%x->FDOUT]", fdc->fdout);
#endif
- /* after a reset, silently believe the FDC will accept commands */
+ /* XXX after a reset, silently believe the FDC will accept commands */
#ifdef PC98
(void)fd_cmd(fdc, 3, NE7CMD_SPECIFY,
NE7_SPEC_1(4, 240), NE7_SPEC_2(2, 0),
@@ -1814,9 +1865,10 @@ fdc_reset(fdc_p fdc)
(void) enable_fifo(fdc);
}
-/****************************************************************************/
-/* fdc in/out */
-/****************************************************************************/
+/*
+ * FDC IO functions, take care of the main status register, timeout
+ * in case the desired status bits are never set.
+ */
static int
fd_in(struct fdc_data *fdc, int *ptr)
{
@@ -1862,9 +1914,10 @@ out_fdc(struct fdc_data *fdc, int x)
return (0);
}
-/****************************************************************************/
-/* fdopen/fdclose */
-/****************************************************************************/
+/*
+ * Block device driver interface functions (interspersed with even more
+ * auxiliary functions).
+ */
int
Fdopen(dev_t dev, int flags, int mode, struct thread *td)
{
@@ -1954,6 +2007,18 @@ Fdopen(dev_t dev, int flags, int mode, struct thread *td)
#endif
fd->ft = fd_types + type - 1;
fd->flags |= FD_OPEN;
+ /*
+ * 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;
}
@@ -1971,13 +2036,10 @@ fdclose(dev_t dev, int flags, int mode, struct thread *td)
return (0);
}
-/****************************************************************************/
-/* fdstrategy */
-/****************************************************************************/
void
fdstrategy(struct bio *bp)
{
- unsigned nblocks, blknum, cando;
+ long blknum, nblocks;
int s;
fdu_t fdu;
fdc_p fdc;
@@ -1994,10 +2056,9 @@ fdstrategy(struct bio *bp)
bp->bio_error = ENXIO;
bp->bio_flags |= BIO_ERROR;
goto bad;
- };
-
+ }
fdblk = 128 << (fd->ft->secsize);
- if (!(bp->bio_cmd & BIO_FORMAT)) {
+ if (bp->bio_cmd != BIO_FORMAT && bp->bio_cmd != BIO_RDSECTID) {
if (bp->bio_blkno < 0) {
printf(
"fd%d: fdstrat: bad request blkno = %lu, bcount = %ld\n",
@@ -2025,30 +2086,26 @@ fdstrategy(struct bio *bp)
bp->bio_flags |= BIO_ERROR;
goto bad;
}
- blknum = (unsigned) bp->bio_blkno * DEV_BSIZE/fdblk;
+ blknum = bp->bio_blkno * DEV_BSIZE / fdblk;
nblocks = fd->ft->size;
- bp->bio_resid = 0;
- if (blknum + (bp->bio_bcount / fdblk) > nblocks) {
- if (blknum <= nblocks) {
- cando = (nblocks - blknum) * fdblk;
- bp->bio_resid = bp->bio_bcount - cando;
- if (cando == 0)
- goto bad; /* not actually bad but EOF */
- } else {
- bp->bio_error = EINVAL;
- bp->bio_flags |= BIO_ERROR;
- goto bad;
+ if (blknum + bp->bio_bcount / fdblk > nblocks) {
+ if (blknum >= nblocks) {
+ if (bp->bio_cmd == BIO_READ)
+ bp->bio_resid = bp->bio_bcount;
+ else {
+ 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 = bp->bio_blkno;
s = splbio();
bioqdisksort(&fdc->head, bp);
untimeout(fd_turnoff, fd, fd->toffhandle); /* a good idea */
-
- /* Tell devstat we are starting on the transaction */
devstat_start_transaction(&fd->device_stats);
device_busy(fd->dev);
-
fdstart(fdc);
splx(s);
return;
@@ -2057,15 +2114,17 @@ 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 *
-\***************************************************************/
+/*
+ * 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)
{
@@ -2107,7 +2166,7 @@ fd_iotimeout(void *xfdc)
splx(s);
}
-/* just ensure it has the right spl */
+/* Just ensure it has the right spl. */
static void
fd_pseudointr(void *xfdc)
{
@@ -2118,11 +2177,12 @@ fd_pseudointr(void *xfdc)
splx(s);
}
-/***********************************************************************\
-* fdintr *
-* keep calling the state machine until it returns a 0 *
-* ALWAYS called at SPLBIO *
-\***********************************************************************/
+/*
+ * fdc_intr
+ *
+ * Keep calling the state machine until it returns a 0.
+ * Always called at splbio.
+ */
static void
fdc_intr(void *xfdc)
{
@@ -2132,8 +2192,8 @@ fdc_intr(void *xfdc)
}
/*
- * magic pseudo-DMA initialization for YE FDC. Sets count and
- * direction
+ * 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, \
@@ -2142,9 +2202,10 @@ fdc_intr(void *xfdc)
((wr ? 0x80 : 0) | ((((cnt)-1) >> 8) & 0x7f)));
/*
- * fdcpio(): perform programmed IO read/write for YE PCMCIA floppy
+ * fdcpio(): perform programmed IO read/write for YE PCMCIA floppy.
*/
-static int fdcpio(fdc_p fdc, long flags, caddr_t addr, u_int count)
+static int
+fdcpio(fdc_p fdc, long flags, caddr_t addr, u_int count)
{
u_char *cptr = (u_char *)addr;
@@ -2152,7 +2213,7 @@ static int fdcpio(fdc_p fdc, long flags, caddr_t addr, u_int count)
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);
@@ -2160,19 +2221,22 @@ static int fdcpio(fdc_p fdc, long flags, caddr_t addr, u_int count)
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);
}
-/***********************************************************************\
-* The controller state machine. *
-* if it returns a non zero value, it should be called again immediatly *
-\***********************************************************************/
+/*
+ * The controller state machine.
+ *
+ * If it returns a non zero value, it should be called again immediately.
+ */
static int
fdstate(fdc_p fdc)
{
- int read, format, head, i, sec = 0, sectrac, st0, cyl, st3, idf;
- unsigned blknum = 0, b_cylinder = 0;
+ struct fdc_readid *idp;
+ int read, format, rdsectid, cylinder, head, i, sec = 0, sectrac;
+ int st0, cyl, st3, idf;
+ unsigned long blknum;
fdu_t fdu = fdc->fdu;
fd_p fd;
register struct bio *bp;
@@ -2188,10 +2252,10 @@ fdstate(fdc_p fdc)
}
}
if (bp == NULL) {
- /***********************************************\
- * nothing left for this controller to do *
- * Force into the IDLE state, *
- \***********************************************/
+ /*
+ * Nothing left for this controller to do,
+ * force into the IDLE state.
+ */
fdc->state = DEVIDLE;
if (fdc->fd) {
device_printf(fdc->fdc_dev,
@@ -2212,17 +2276,10 @@ fdstate(fdc_p fdc)
idf = ISADMA_READ;
else
idf = ISADMA_WRITE;
- format = bp->bio_cmd & BIO_FORMAT;
- if (format) {
+ format = bp->bio_cmd == BIO_FORMAT;
+ rdsectid = bp->bio_cmd == BIO_RDSECTID;
+ if (format)
finfo = (struct fd_formb *)bp->bio_data;
- fd->skip = (char *)&(finfo->fd_formb_cylno(0))
- - (char *)finfo;
- }
- if (fdc->state == DOSEEK || fdc->state == SEEKCOMPLETE) {
- blknum = (unsigned) bp->bio_pblkno * DEV_BSIZE/fdblk +
- fd->skip/fdblk;
- b_cylinder = blknum / (fd->ft->sectrac * fd->ft->heads);
- }
TRACE1("fd%d", fdu);
TRACE1("[%s]", fdstates[fdc->state]);
TRACE1("(0x%x)", fd->flags);
@@ -2263,17 +2320,17 @@ fdstate(fdc_p fdc)
fdc->fdctl_wr(fdc, fd->ft->trans);
#endif
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 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); /* come back later */
+ return (0); /* will return later */
}
- /*******************************************************\
- * Maybe if it's not starting, it SHOULD be starting *
- \*******************************************************/
+ /*
+ * Maybe if it's not starting, it SHOULD be starting.
+ */
#ifdef EPSON_NRDISK
if (fdu != nrdu) {
if (!(fd->flags & FD_MOTOR))
@@ -2292,7 +2349,7 @@ fdstate(fdc_p fdc)
{
fdc->state = MOTORWAIT;
fd_turnon(fd);
- return (0);
+ return (0); /* will return later */
}
else /* at least make sure we are selected */
{
@@ -2304,22 +2361,29 @@ fdstate(fdc_p fdc)
fdc->flags &= ~FDC_NEEDS_RESET;
} else
fdc->state = DOSEEK;
- break;
+ return (1); /* will return immediately */
+
case DOSEEK:
- if (b_cylinder == (unsigned)fd->track)
+#ifdef PC98
+ blknum = bp->bio_pblkno * DEV_BSIZE / fdblk + fd->skip / fdblk;
+#else
+ blknum = bp->bio_pblkno + fd->skip / fdblk;
+#endif
+ cylinder = blknum / (fd->ft->sectrac * fd->ft->heads);
+ if (cylinder == fd->track)
{
fdc->state = SEEKCOMPLETE;
- break;
+ return (1); /* will return immediately */
}
#ifdef PC98
pc98_fd_check_ready(fdu);
#endif
if (fd_cmd(fdc, 3, NE7CMD_SEEK,
- fd->fdsu, b_cylinder * fd->ft->steptrac,
+ fd->fdsu, cylinder * fd->ft->steptrac,
0))
{
/*
- * seek command not accepted, looks like
+ * Seek command not accepted, looks like
* the FDC went off to the Saints...
*/
fdc->retry = 6; /* try a reset */
@@ -2328,15 +2392,24 @@ fdstate(fdc_p 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 */
- /* Make sure seek really happened*/
+
+ case SEEKCOMPLETE : /* seek done, start DMA */
+#ifdef PC98
+ blknum = bp->bio_pblkno * DEV_BSIZE / fdblk + fd->skip / fdblk;
+#else
+ blknum = bp->bio_pblkno + fd->skip / fdblk;
+#endif
+ cylinder = blknum / (fd->ft->sectrac * fd->ft->heads);
+
+ /* Make sure seek really happened. */
if(fd->track == FD_NO_TRACK) {
- int descyl = b_cylinder * fd->ft->steptrac;
+ int descyl = cylinder * fd->ft->steptrac;
do {
/*
* This might be a "ready changed" interrupt,
@@ -2361,10 +2434,10 @@ fdstate(fdc_p fdc)
*/
if (fd_sense_int(fdc, &st0, &cyl)
== FD_NOT_VALID)
- return 0;
+ 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 */
+ return (0); /* hope for a real intr */
} while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
if (0 == descyl) {
@@ -2405,20 +2478,28 @@ fdstate(fdc_p fdc)
}
}
- fd->track = b_cylinder;
+ fd->track = cylinder;
+ if (format)
+ fd->skip = (char *)&(finfo->fd_formb_cylno(0))
+ - (char *)finfo;
#ifdef EPSON_NRDISK
if (fdu != nrdu) {
#endif /* EPSON_NRDISK */
- if (!(fdc->flags & FDC_NODMA))
+ if (!rdsectid && !(fdc->flags & FDC_NODMA))
isa_dmastart(idf, bp->bio_data+fd->skip,
format ? bp->bio_bcount : fdblk, fdc->dmachan);
+#ifdef PC98
+ blknum = bp->bio_pblkno * DEV_BSIZE / fdblk + fd->skip / fdblk;
+#else
+ blknum = bp->bio_pblkno + fd->skip / fdblk;
+#endif
sectrac = fd->ft->sectrac;
sec = blknum % (sectrac * fd->ft->heads);
head = sec / sectrac;
sec = sec % sectrac + 1;
fd->hddrv = ((head&1)<<2)+fdu;
- if(format || !read)
+ if(format || !(read || rdsectid))
{
/* make sure the drive is writable */
if(fd_sense_drive_status(fdc, &st3) != 0)
@@ -2449,7 +2530,7 @@ fdstate(fdc_p fdc)
fdc->status[5] = sec;
fdc->retry = 8; /* break out immediately */
fdc->state = IOTIMEDOUT; /* not really... */
- return (1);
+ return (1); /* will return immediately */
}
}
@@ -2489,17 +2570,24 @@ fdstate(fdc_p fdc)
fdc->retry = 6;
return (retrier(fdc));
}
+ } else if (rdsectid) {
+ if (fd_cmd(fdc, 2, NE7CMD_READID, head << 2 | fdu, 0)) {
+ /* controller jamming */
+ fdc->retry = 6;
+ return (retrier(fdc));
+ }
} else {
+ /* read or write operation */
if (fdc->flags & FDC_NODMA) {
/*
- * this seems to be necessary even when
- * reading data
+ * 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
+ * Perform the write pseudo-DMA before
+ * the WRITE command is sent.
*/
if (!read)
(void)fdcpio(fdc,bp->bio_cmd,
@@ -2527,20 +2615,20 @@ fdstate(fdc_p fdc)
return (retrier(fdc));
}
}
- if (fdc->flags & FDC_NODMA)
+ if (!rdsectid && (fdc->flags & FDC_NODMA))
/*
- * if this is a read, then simply await interrupt
- * before performing PIO
+ * 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
+ * Write (or format) operation will fall through and
+ * await completion interrupt.
*/
fdc->state = IOCOMPLETE;
fd->tohandle = timeout(fd_iotimeout, fdc, hz);
@@ -2575,15 +2663,16 @@ fdstate(fdc_p fdc)
fdc->state = IOCOMPLETE;
}
#endif
+
case PIOREAD:
/*
- * actually perform the PIO read. The IOCOMPLETE case
- * removes the timeout for us.
+ * 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 */
+ case IOCOMPLETE: /* IO done, post-analyze */
#ifdef EPSON_NRDISK
if (fdu != nrdu)
untimeout(fd_iotimeout, fdc, fd->tohandle);
@@ -2591,8 +2680,8 @@ fdstate(fdc_p fdc)
untimeout(fd_iotimeout, fdc, fd->tohandle);
#endif
- if (fd_read_status(fdc, fd->fdsu)) {
- if (!(fdc->flags & FDC_NODMA))
+ 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);
@@ -2604,12 +2693,11 @@ fdstate(fdc_p fdc)
fdc->state = IOTIMEDOUT;
/* FALLTHROUGH */
-
case IOTIMEDOUT:
#ifdef EPSON_NRDISK
if (fdu != nrdu) {
#endif /* EPSON_NRDISK */
- if (!(fdc->flags & FDC_NODMA))
+ if (!rdsectid && !(fdc->flags & FDC_NODMA))
isa_dmadone(idf, bp->bio_data + fd->skip,
format ? bp->bio_bcount : fdblk, fdc->dmachan);
#ifdef EPSON_NRDISK
@@ -2620,16 +2708,23 @@ fdstate(fdc_p fdc)
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.
- * Just restart it, don't increment retry
- * count. (vak)
- */
- fdc->state = SEEKCOMPLETE;
- return (1);
+ * 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 */
}
- else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_IV
+ 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
@@ -2639,13 +2734,24 @@ fdstate(fdc_p fdc)
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 (!format && fd->skip < bp->bio_bcount - bp->bio_resid) {
+ 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);
@@ -2653,12 +2759,14 @@ fdstate(fdc_p fdc)
fdc->fdu = -1;
fdc->state = FINDWORK;
}
- return (1);
+ return (1); /* will return immediately */
+
case RESETCTLR:
fdc_reset(fdc);
fdc->retry++;
fdc->state = RESETCOMPLETE;
- return (0);
+ return (0); /* will return later */
+
case RESETCOMPLETE:
/*
* Discard all the results from the reset so that they
@@ -2667,7 +2775,7 @@ fdstate(fdc_p fdc)
for (i = 0; i < 4; i++)
(void)fd_sense_int(fdc, &st0, &cyl);
fdc->state = STARTRECAL;
- /* Fall through. */
+ /* FALLTHROUGH */
case STARTRECAL:
#ifdef PC98
pc98_fd_check_ready(fdu);
@@ -2679,21 +2787,23 @@ fdstate(fdc_p 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;
+ 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 */
+ return (0); /* hope for a real intr */
} while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
#ifdef EPSON_NRDISK
if (fdu == nrdu) {
@@ -2705,12 +2815,12 @@ fdstate(fdc_p fdc)
{
if(fdc->retry > 3)
/*
- * a recalibrate from beyond cylinder 77
+ * 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
+ * time in a line.
*/
printf("fd%d: recal failed ST0 %b cyl %d\n",
fdu, st0, NE7_ST0BITS, cyl);
@@ -2720,7 +2830,8 @@ fdstate(fdc_p fdc)
fd->track = 0;
/* Seek (probably) necessary */
fdc->state = DOSEEK;
- return (1); /* will return immediatly */
+ return (1); /* will return immediately */
+
case MOTORWAIT:
if(fd->flags & FD_MOTOR_WAIT)
{
@@ -2729,19 +2840,13 @@ fdstate(fdc_p fdc)
if (fdc->flags & FDC_NEEDS_RESET) {
fdc->state = RESETCTLR;
fdc->flags &= ~FDC_NEEDS_RESET;
- } else {
- /*
- * If all motors were off, then the controller was
- * reset, so it has lost track of the current
- * cylinder. Recalibrate to handle this case.
- * But first, discard the results of the reset.
- */
- fdc->state = RESETCOMPLETE;
- }
- return (1); /* will return immediatly */
+ } else
+ fdc->state = DOSEEK;
+ return (1); /* will return immediately */
+
default:
device_printf(fdc->fdc_dev, "unexpected FD int->");
- if (fd_read_status(fdc, fd->fdsu) == 0)
+ if (fd_read_status(fdc) == 0)
printf("FDC status :%x %x %x %x %x %x %x ",
fdc->status[0],
fdc->status[1],
@@ -2755,13 +2860,12 @@ fdstate(fdc_p fdc)
if (fd_sense_int(fdc, &st0, &cyl) != 0)
{
printf("[controller is dead now]\n");
- return (0);
+ return (0); /* will return later */
}
printf("ST0 = %x, PCN = %x\n", st0, cyl);
- return (0);
+ return (0); /* will return later */
}
- /*XXX confusing: some branches return immediately, others end up here*/
- return (1); /* Come back immediatly to new state */
+ /* noone should ever get here */
}
static int
@@ -2793,32 +2897,27 @@ retrier(struct fdc_data *fdc)
break;
default:
fail:
- {
- int printerror = (fd->options & FDOPT_NOERRLOG) == 0;
-
- if (printerror)
- diskerr(bp, "hard error", fdc->fd->skip / DEV_BSIZE,
- (struct disklabel *)NULL);
- if (printerror) {
- 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_NOERRLOG) == 0) {
+ diskerr(bp, "hard error", fdc->fd->skip / DEV_BSIZE,
+ (struct disklabel *)NULL);
+ 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;
- }
+ 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);
@@ -2840,150 +2939,132 @@ fdbiodone(struct bio *bp)
}
static int
-fdformat(dev, finfo, td)
- dev_t dev;
- struct fd_formb *finfo;
- struct thread *td;
+fdmisccmd(dev_t dev, u_int cmd, void *data)
{
- struct proc *p = td->td_proc;
- fdu_t fdu;
- fd_p fd;
-
+ fdu_t fdu;
+ fd_p fd;
struct bio *bp;
- int rv = 0, s;
+ struct fd_formb *finfo;
+ struct fdc_readid *idfield;
size_t fdblk;
- fdu = FDUNIT(minor(dev));
- fd = devclass_get_softc(fd_devclass, fdu);
+ fdu = FDUNIT(minor(dev));
+ fd = devclass_get_softc(fd_devclass, fdu);
fdblk = 128 << fd->ft->secsize;
+ finfo = (struct fd_formb *)data;
+ idfield = (struct fdc_readid *)data;
- /* set up a buffer header for fdstrategy() */
- bp = (struct bio *)malloc(sizeof(struct bio), M_TEMP, M_NOWAIT);
- if(bp == 0)
- return ENOMEM;
- /*
- * keep the process from being swapped
- */
- PHOLD(p);
- bzero((void *)bp, sizeof(*bp));
- bp->bio_cmd = BIO_FORMAT;
+ bp = malloc(sizeof(struct bio), M_TEMP, M_ZERO);
/*
- * calculate a fake blkno, so fdstrategy() would initiate a
- * seek to the requested cylinder
+ * Set up a bio request for fdstrategy(). bio_blkno is faked
+ * so that fdstrategy() will seek to the the requested
+ * cylinder, and use the desired head. Since we are not
+ * interested in bioqdisksort() munging with our faked bio
+ * request, we mark it as being an ordered request.
*/
- bp->bio_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads)
- + finfo->head * fd->ft->sectrac) * fdblk / DEV_BSIZE;
-
- bp->bio_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
- bp->bio_data = (caddr_t)finfo;
-
- /* now do the format */
+ bp->bio_cmd = cmd;
+ if (cmd == BIO_FORMAT) {
+ bp->bio_blkno =
+ (finfo->cyl * (fd->ft->sectrac * fd->ft->heads) +
+ finfo->head * fd->ft->sectrac) *
+ fdblk / DEV_BSIZE;
+ bp->bio_bcount = sizeof(struct fd_idfield_data) *
+ finfo->fd_formb_nsecs;
+ } else if (cmd == BIO_RDSECTID) {
+ bp->bio_blkno =
+ (idfield->cyl * (fd->ft->sectrac * fd->ft->heads) +
+ idfield->head * fd->ft->sectrac) *
+ fdblk / DEV_BSIZE;
+ 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;
- fdstrategy(bp);
+ bp->bio_flags = BIO_ORDERED;
- /* ...and wait for it to complete */
- s = splbio();
- while(!(bp->bio_flags & BIO_DONE)) {
- rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
- if (rv == EWOULDBLOCK)
- break;
- }
- splx(s);
-
- if (rv == EWOULDBLOCK) {
- /* timed out */
- rv = EIO;
- device_unbusy(fd->dev);
- }
- if (bp->bio_flags & BIO_ERROR)
- rv = bp->bio_error;
/*
- * allow the process to be swapped
+ * Now run the command. The wait loop is a version of bufwait()
+ * adapted for struct bio instead of struct buf and specialized
+ * for the current context.
*/
- PRELE(p);
+ fdstrategy(bp);
+ while ((bp->bio_flags & BIO_DONE) == 0)
+ tsleep(bp, PRIBIO, "fdcmd", 0);
+
free(bp, M_TEMP);
- return rv;
+ return (bp->bio_flags & BIO_ERROR ? bp->bio_error : 0);
}
-/*
- * TODO: don't allocate buffer on stack.
- */
-
static int
-fdioctl(dev, cmd, addr, flag, td)
- dev_t dev;
- u_long cmd;
- caddr_t addr;
- int flag;
- struct thread *td;
+fdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
{
- fdu_t fdu = FDUNIT(minor(dev));
- fd_p fd = devclass_get_softc(fd_devclass, fdu);
- size_t fdblk;
-
+ fdu_t fdu;
+ fd_p fd;
struct fd_type *fdt;
- struct disklabel *dl;
+ struct disklabel *lp;
struct fdc_status *fsp;
- char buffer[DEV_BSIZE];
- int error = 0;
+ struct fdc_readid *rid;
+ size_t fdblk;
+ int error;
- fdblk = 128 << fd->ft->secsize;
+ fdu = FDUNIT(minor(dev));
+ fd = devclass_get_softc(fd_devclass, fdu);
#ifdef PC98
pc98_fd_check_ready(fdu);
#endif
+
+ fdblk = 128 << fd->ft->secsize;
+ error = 0;
+
switch (cmd) {
case DIOCGDINFO:
- bzero(buffer, sizeof (buffer));
- dl = (struct disklabel *)buffer;
- dl->d_secsize = fdblk;
+ lp = malloc(sizeof(*lp), M_TEMP, M_ZERO);
+ lp->d_secsize = fdblk;
fdt = fd->ft;
- dl->d_secpercyl = fdt->size / fdt->tracks;
- dl->d_type = DTYPE_FLOPPY;
-
- if (readdisklabel(dkmodpart(dev, RAW_PART), dl)
- == NULL)
- error = 0;
- else
+ lp->d_secpercyl = fdt->size / fdt->tracks;
+ lp->d_type = DTYPE_FLOPPY;
+ if (readdisklabel(dkmodpart(dev, RAW_PART), lp) != NULL)
error = EINVAL;
-
- *(struct disklabel *)addr = *dl;
+ else
+ *(struct disklabel *)addr = *lp;
+ free(lp, M_TEMP);
break;
case DIOCSDINFO:
if ((flag & FWRITE) == 0)
- error = EBADF;
+ return (EBADF);
+ /*
+ * XXX perhaps should call setdisklabel() to do error checking
+ * although there is nowhere to "set" the result. Perhaps
+ * should always just fail.
+ */
break;
case DIOCWLABEL:
if ((flag & FWRITE) == 0)
- error = EBADF;
+ return (EBADF);
break;
case DIOCWDINFO:
- if ((flag & FWRITE) == 0) {
- error = EBADF;
- break;
- }
-
- dl = (struct disklabel *)addr;
-
- if ((error = setdisklabel((struct disklabel *)buffer, dl,
- (u_long)0)) != 0)
- break;
-
- error = writedisklabel(dev, (struct disklabel *)buffer);
+ if ((flag & FWRITE) == 0)
+ return (EBADF);
+ lp = malloc(DEV_BSIZE, M_TEMP, M_ZERO);
+ error = setdisklabel(lp, (struct disklabel *)addr, (u_long)0);
+ if (error != 0)
+ error = writedisklabel(dev, lp);
+ free(lp, M_TEMP);
break;
+
case FD_FORM:
if ((flag & FWRITE) == 0)
- error = EBADF; /* must be opened for writing */
- else if (((struct fd_formb *)addr)->format_version !=
- FD_FORMAT_VERSION)
- error = EINVAL; /* wrong version of formatting prog */
- else
- error = fdformat(dev, (struct fd_formb *)addr, td);
+ 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, BIO_FORMAT, addr);
break;
case FD_GTYPE: /* get drive type */
@@ -2993,7 +3074,7 @@ fdioctl(dev, cmd, addr, flag, td)
case FD_STYPE: /* set drive type */
/* this is considered harmful; only allow for superuser */
if (suser_td(td) != 0)
- return EPERM;
+ return (EPERM);
*fd->ft = *(struct fd_type *)addr;
break;
@@ -3005,39 +3086,39 @@ fdioctl(dev, cmd, addr, flag, td)
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(td) != 0)
- return EPERM;
+ 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;
+ 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, BIO_RDSECTID, addr);
+ break;
+
default:
error = ENOTTY;
break;
}
return (error);
}
-
-/*
- * Hello emacs, these are the
- * Local Variables:
- * c-indent-level: 8
- * c-continued-statement-offset: 8
- * c-continued-brace-offset: 0
- * c-brace-offset: -8
- * c-brace-imaginary-offset: 0
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c++-hanging-braces: 1
- * c++-access-specifier-offset: -8
- * c++-empty-arglist-indent: 8
- * c++-friend-offset: 0
- * End:
- */
diff --git a/sys/pc98/pc98/fd.c b/sys/pc98/pc98/fd.c
index bbf8b37..93eaf77 100644
--- a/sys/pc98/pc98/fd.c
+++ b/sys/pc98/pc98/fd.c
@@ -29,6 +29,13 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -44,7 +51,6 @@
*
* from: @(#)fd.c 7.4 (Berkeley) 5/25/91
* $FreeBSD$
- *
*/
#include "opt_fdc.h"
@@ -67,7 +73,6 @@
#include <sys/proc.h>
#include <sys/syslog.h>
-#include <sys/bus.h>
#include <machine/bus.h>
#include <sys/rman.h>
@@ -223,6 +228,13 @@ FDC_ACCESSOR(fdunit, FDUNIT, int)
#define FD_FAILED -1
#define FD_NOT_VALID -2
#define FDC_ERRMAX 100 /* do not log more */
+/*
+ * 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.
+ */
+#define FDC_DMAOV_MAX 25
#ifdef PC98
#define NUMTYPES 12
@@ -232,7 +244,7 @@ FDC_ACCESSOR(fdunit, FDUNIT, int)
#define NUMDENS (NUMTYPES - 7)
#endif
-#define NO_TYPE 0 /* must match NO_TYPE in ft.c */
+#define NO_TYPE 0
#define FD_1720 1
#define FD_1480 2
#define FD_1440 3
@@ -261,6 +273,7 @@ FDC_ACCESSOR(fdunit, FDUNIT, int)
#define FD_640in5_25 17
#endif
+#define BIO_RDSECTID BIO_CMD1
static struct fd_type fd_types[NUMTYPES] =
{
@@ -314,16 +327,15 @@ static bus_addr_t fdc_iat[] = {0, 2, 4};
#endif
#define MAX_SEC_SIZE (128 << 3)
+#define MAX_CYLINDER 85 /* some people really stress their drives
+ * up to cyl 82 */
+#define MAX_HEAD 1
-/***********************************************************************\
-* Per controller structure. *
-\***********************************************************************/
static devclass_t fdc_devclass;
-/***********************************************************************\
-* Per drive structure. *
-* N per controller (DRVS_PER_CTLR) *
-\***********************************************************************/
+/*
+ * Per drive structure (softc).
+ */
struct fd_data {
struct fdc_data *fdc; /* pointer to controller structure */
int fdsu; /* this units number on this controller */
@@ -339,12 +351,16 @@ struct fd_data {
#define FD_NO_TRACK -2
int track; /* where we think the head is */
int options; /* user configurable options, see ioctl_fd.h */
- struct callout_handle toffhandle;
- struct callout_handle tohandle;
- struct devstat device_stats;
#ifdef PC98
int pc98_trans;
#endif
+ struct callout_handle toffhandle;
+ struct callout_handle tohandle;
+ struct devstat device_stats;
+ eventhandler_tag clonetag;
+ dev_t masterdev;
+#define NCLONEDEVS 10 /* must match the table below */
+ dev_t clonedevs[NCLONEDEVS];
device_t dev;
fdu_t fdu;
};
@@ -404,17 +420,61 @@ nrd_info(addr)
}
#endif /* EPSON_NRDISK */
-/***********************************************************************\
-* 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) *
-\***********************************************************************/
-
-/* internal functions */
-static void fdc_intr(void *);
+/*
+ * 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)
+ */
+
+/*
+ * 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.
+ */
+#ifndef PC98
+static void fdout_wr(fdc_p, u_int8_t);
+#endif
+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);
+#ifndef PC98
+static void fdctl_wr_isa(fdc_p, u_int8_t);
+#if NCARD > 0
+static void fdctl_wr_pcmcia(fdc_p, u_int8_t);
+#endif
+#endif /* PC98 */
+#if 0
+static u_int8_t fdin_rd(fdc_p);
+#endif
+static int fdc_err(struct fdc_data *, const char *);
+static int fd_cmd(struct fdc_data *, int, ...);
+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 fdc_alloc_resources(struct fdc_data *);
+static void fdc_release_resources(struct fdc_data *);
+static int fdc_read_ivar(device_t, device_t, int, uintptr_t *);
+static int fdc_probe(device_t);
+#if NCARD > 0
+static int fdc_pccard_probe(device_t);
+#endif
+static int fdc_detach(device_t dev);
+static void fdc_add_child(device_t, const char *, int);
+static int fdc_attach(device_t);
+static int fdc_print_child(device_t, device_t);
+static void fd_clone (void *, char *, int, dev_t *);
+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
@@ -424,46 +484,39 @@ 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);
+/*
+ * The open function is named Fdopen() to avoid confusion with fdopen()
+ * in fd(4). The difference is now only meaningful for debuggers.
+ */
+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 fdstate(struct fdc_data *);
static int retrier(struct fdc_data *);
-static int fdformat(dev_t, struct fd_formb *, struct thread *);
-
-static int enable_fifo(fdc_p fdc);
-static void fd_clone (void *arg, char *name, int namelen, dev_t *dev);
+static void fdbiodone(struct bio *);
+static int fdmisccmd(dev_t, u_int, void *);
+static d_ioctl_t fdioctl;
static int fifo_threshold = 8; /* XXX: should be accessible via sysctl */
#ifdef FDC_DEBUG
-static char const * const fdstates[] =
-{
-"DEVIDLE",
-"FINDWORK",
-"DOSEEK",
-"SEEKCOMPLETE",
-"IOCOMPLETE",
-"RECALCOMPLETE",
-"STARTRECAL",
-"RESETCTLR",
-"SEEKWAIT",
-"RECALWAIT",
-"MOTORWAIT",
-"IOTIMEDOUT",
-"RESETCOMPLETE",
-"PIOREAD",
-};
-
/* CAUTION: fd_debug causes huge amounts of logging output */
static int volatile fd_debug = 0;
-#define TRACE0(arg) if(fd_debug) printf(arg)
-#define TRACE1(arg1, arg2) if(fd_debug) printf(arg1, arg2)
+#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)
-#define TRACE1(arg1, arg2)
+#define TRACE0(arg) do { } while (0)
+#define TRACE1(arg1, arg2) do { } while (0)
#endif /* FDC_DEBUG */
+/*
+ * Bus space handling (access to low-level IO).
+ */
#ifndef PC98
static void
fdout_wr(fdc_p fdc, u_int8_t v)
@@ -524,17 +577,7 @@ fdin_rd(fdc_p fdc)
#endif
-/*
- * named Fdopen() to avoid confusion with fdopen() in fd(4); the
- * difference is now only meaningful for debuggers
- */
-static d_open_t Fdopen;
-static d_close_t fdclose;
-static d_ioctl_t fdioctl;
-static d_strategy_t fdstrategy;
-
#define CDEV_MAJOR 9
-
static struct cdevsw fd_cdevsw = {
/* open */ Fdopen,
/* close */ fdclose,
@@ -551,6 +594,10 @@ static struct cdevsw fd_cdevsw = {
/* flags */ D_DISK,
};
+/*
+ * Auxiliary functions. Well, some only. Others are scattered
+ * throughout the entire file.
+ */
static int
fdc_err(struct fdc_data *fdc, const char *s)
{
@@ -712,13 +759,13 @@ fd_sense_int(fdc_p fdc, int *st0p, int *cylp)
static int
-fd_read_status(fdc_p fdc, int fdsu)
+fd_read_status(fdc_p fdc)
{
int i, ret;
- for (i = 0; i < 7; i++) {
+ for (i = ret = 0; i < 7; i++) {
/*
- * XXX types are poorly chosen. Only bytes can by read
+ * XXX types are poorly chosen. Only bytes can be read
* from the hardware, but fdc->status[] wants u_ints and
* fd_in() gives ints.
*/
@@ -757,9 +804,6 @@ fd_read_status(fdc_p fdc, int fdsu)
return ret;
}
-/****************************************************************************/
-/* autoconfiguration stuff */
-/****************************************************************************/
#ifdef PC98
static int pc98_trans = 0; /* 0 : HD , 1 : DD , 2 : 1.44 */
static int pc98_trans_prev = 0;
@@ -807,13 +851,17 @@ static int
fdc_alloc_resources(struct fdc_data *fdc)
{
device_t dev;
- int ispnp, ispcmcia;
#ifdef PC98
int rid;
+#else
+ int ispnp, ispcmcia, nports;
#endif
+
dev = fdc->fdc_dev;
+#ifndef PC98
ispnp = (fdc->flags & FDC_ISPNP) != 0;
ispcmcia = (fdc->flags & FDC_ISPCMCIA) != 0;
+#endif
fdc->rid_ioport = fdc->rid_irq = fdc->rid_drq = 0;
fdc->res_ioport = fdc->res_irq = fdc->res_drq = 0;
@@ -821,6 +869,11 @@ fdc_alloc_resources(struct fdc_data *fdc)
fdc->res_ioport = isa_alloc_resourcev(dev, SYS_RES_IOPORT,
&fdc->rid_ioport, fdc_iat,
3, RF_ACTIVE);
+ if (fdc->res_ioport == 0) {
+ device_printf(dev, "cannot reserve I/O port range\n");
+ return ENXIO;
+ }
+ isa_load_resourcev(fdc->res_ioport, fdc_iat, 3);
#else
/*
* On standard ISA, we don't just use an 8 port range
@@ -833,17 +886,15 @@ fdc_alloc_resources(struct fdc_data *fdc)
* uses the register with offset 6 for pseudo-DMA, and the
* one with offset 7 as control register.
*/
+ nports = ispcmcia ? 8 : (ispnp ? 1 : 6);
fdc->res_ioport = bus_alloc_resource(dev, SYS_RES_IOPORT,
&fdc->rid_ioport, 0ul, ~0ul,
- ispcmcia ? 8 : (ispnp ? 1 : 6),
- RF_ACTIVE);
-#endif
+ nports, RF_ACTIVE);
if (fdc->res_ioport == 0) {
- device_printf(dev, "cannot reserve I/O port range\n");
+ device_printf(dev, "cannot reserve I/O port range (%d ports)\n",
+ nports);
return ENXIO;
}
-#ifdef PC98
- isa_load_resourcev(fdc->res_ioport, fdc_iat, 3);
#endif
fdc->portt = rman_get_bustag(fdc->res_ioport);
fdc->porth = rman_get_bushandle(fdc->res_ioport);
@@ -911,7 +962,7 @@ fdc_alloc_resources(struct fdc_data *fdc)
0ul, ~0ul, 1, RF_ACTIVE);
if (fdc->res_ctl == 0) {
device_printf(dev,
- "cannot reserve control I/O port range\n");
+ "cannot reserve control I/O port range (control port)\n");
return ENXIO;
}
fdc->ctlt = rman_get_bustag(fdc->res_ctl);
@@ -987,9 +1038,9 @@ fdc_release_resources(struct fdc_data *fdc)
}
}
-/****************************************************************************/
-/* autoconfiguration stuff */
-/****************************************************************************/
+/*
+ * Configuration/initialization stuff, per controller.
+ */
static struct isa_pnp_id fdc_ids[] = {
{0x0007d041, "PC standard floppy disk controller"}, /* PNP0700 */
@@ -1012,9 +1063,6 @@ fdc_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
return 0;
}
-/*
- * fdc controller section.
- */
static int
fdc_probe(device_t dev)
{
@@ -1125,11 +1173,19 @@ fdc_pccard_probe(device_t dev)
#endif
/* see if it can handle a command */
+#ifdef PC98
+ if (fd_cmd(fdc, 3, NE7CMD_SPECIFY, NE7_SPEC_1(4, 240),
+ NE7_SPEC_2(2, 0), 0)) {
+ error = ENXIO;
+ goto out;
+ }
+#else
if (fd_cmd(fdc, 3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240),
NE7_SPEC_2(2, 0), 0)) {
error = ENXIO;
goto out;
}
+#endif
device_set_desc(dev, "Y-E Data PCMCIA floppy");
fdc->fdct = FDC_NE765;
@@ -1139,8 +1195,10 @@ out:
return (error);
}
+#endif /* NCARD > 0 */
+
static int
-fdc_pccard_detach(device_t dev)
+fdc_detach(device_t dev)
{
struct fdc_data *fdc;
int error;
@@ -1151,6 +1209,17 @@ fdc_pccard_detach(device_t dev)
if ((error = bus_generic_detach(dev)))
return (error);
+#ifdef PC98
+ /* reset controller, turn motor off */
+ fdc_reset(fdc);
+#else
+ /* reset controller, turn motor off */
+ fdout_wr(fdc, 0);
+#endif
+
+ if ((fdc->flags & FDC_NODMA) == 0)
+ isa_dma_release(fdc->dmachan);
+
if ((fdc->flags & FDC_ATTACHED) == 0) {
device_printf(dev, "already unloaded\n");
return (0);
@@ -1164,8 +1233,6 @@ fdc_pccard_detach(device_t dev)
return (0);
}
-#endif /* NCARD > 0 */
-
/*
* Add a child device to the fdc controller. It will then be probed etc.
*/
@@ -1194,8 +1261,8 @@ static int
fdc_attach(device_t dev)
{
struct fdc_data *fdc;
- int i, error, dunit;
const char *name, *dname;
+ int i, error, dunit;
fdc = device_get_softc(dev);
error = fdc_alloc_resources(fdc);
@@ -1211,7 +1278,7 @@ fdc_attach(device_t dev)
return error;
}
fdc->fdcu = device_get_unit(dev);
- fdc->flags |= FDC_ATTACHED;
+ fdc->flags |= FDC_ATTACHED | FDC_NEEDS_RESET;
if ((fdc->flags & FDC_NODMA) == 0) {
/*
@@ -1229,7 +1296,7 @@ fdc_attach(device_t dev)
fdc_reset(fdc);
#else
/* reset controller, turn motor off, clear fdout mirror reg */
- fdout_wr(fdc, ((fdc->fdout = 0)));
+ fdout_wr(fdc, fdc->fdout = 0);
#endif
bioq_init(&fdc->head);
@@ -1242,7 +1309,10 @@ fdc_attach(device_t dev)
while ((resource_find_match(&i, &dname, &dunit, "at", name)) == 0)
fdc_add_child(dev, dname, dunit);
- return (bus_generic_attach(dev));
+ if ((error = bus_generic_attach(dev)) != 0)
+ return (error);
+
+ return (0);
}
static int
@@ -1261,7 +1331,7 @@ static device_method_t fdc_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, fdc_probe),
DEVMETHOD(device_attach, fdc_attach),
- DEVMETHOD(device_detach, bus_generic_detach),
+ DEVMETHOD(device_detach, fdc_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),
DEVMETHOD(device_resume, bus_generic_resume),
@@ -1291,7 +1361,7 @@ static device_method_t fdc_pccard_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, fdc_pccard_probe),
DEVMETHOD(device_attach, fdc_attach),
- DEVMETHOD(device_detach, fdc_pccard_detach),
+ DEVMETHOD(device_detach, fdc_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),
DEVMETHOD(device_resume, bus_generic_resume),
@@ -1319,14 +1389,10 @@ static struct {
int minor;
int link;
} fd_suffix[] = {
- { "a", 0, 1 },
- { "b", 0, 1 },
- { "c", 0, 1 },
- { "d", 0, 1 },
- { "e", 0, 1 },
- { "f", 0, 1 },
- { "g", 0, 1 },
- { "h", 0, 1 },
+ /*
+ * Genuine clone devices must come first, and their number must
+ * match NCLONEDEVS above.
+ */
{ ".1720", 1, 0 },
{ ".1480", 2, 0 },
{ ".1440", 3, 0 },
@@ -1341,15 +1407,25 @@ static struct {
{ ".1280", 11, 0 },
{ ".1476", 12, 0 },
#endif
+ { "a", 0, 1 },
+ { "b", 0, 1 },
+ { "c", 0, 1 },
+ { "d", 0, 1 },
+ { "e", 0, 1 },
+ { "f", 0, 1 },
+ { "g", 0, 1 },
+ { "h", 0, 1 },
{ 0, 0 }
};
+
static void
-fd_clone (void *arg, char *name, int namelen, dev_t *dev)
+fd_clone(void *arg, char *name, int namelen, dev_t *dev)
{
+ struct fd_data *fd;
int u, d, i;
char *n;
- dev_t pdev;
+ fd = (struct fd_data *)arg;
if (*dev != NODEV)
return;
if (dev_stdclone(name, &n, "fd", &u) != 2)
@@ -1365,15 +1441,14 @@ fd_clone (void *arg, char *name, int namelen, dev_t *dev)
if (fd_suffix[i].link == 0) {
*dev = make_dev(&fd_cdevsw, (u << 6) + d,
UID_ROOT, GID_OPERATOR, 0640, name);
+ fd->clonedevs[i] = *dev;
} else {
- pdev = makedev(fd_cdevsw.d_maj, (u << 6) + d);
- *dev = make_dev_alias(pdev, name);
+ *dev = make_dev_alias(fd->masterdev, name);
}
}
-/******************************************************************/
/*
- * devices attached to the controller section.
+ * Configuration/initialization, per drive.
*/
static int
fd_probe(device_t dev)
@@ -1475,6 +1550,7 @@ fd_probe(device_t dev)
#ifndef PC98
/* select it */
set_motor(fdc, fdsu, TURNON);
+ fdc_reset(fdc); /* XXX reset, then unreset, etc. */
DELAY(1000000); /* 1 sec */
/* XXX This doesn't work before the first set_motor() */
@@ -1607,21 +1683,19 @@ static int
fd_attach(device_t dev)
{
struct fd_data *fd;
- static int cdevsw_add_done = 0;
-
- fd = device_get_softc(dev);
+ static int cdevsw_add_done;
+ int i;
if (!cdevsw_add_done) {
cdevsw_add(&fd_cdevsw); /* XXX */
- cdevsw_add_done++;
+ cdevsw_add_done = 1;
}
- EVENTHANDLER_REGISTER(dev_clone, fd_clone, 0, 1000);
- make_dev(&fd_cdevsw, (fd->fdu << 6),
- UID_ROOT, GID_OPERATOR, 0640, "fd%d", fd->fdu);
-
- /*
- * Export the drive to the devstat interface.
- */
+ fd = device_get_softc(dev);
+ fd->clonetag = EVENTHANDLER_REGISTER(dev_clone, fd_clone, fd, 1000);
+ fd->masterdev = make_dev(&fd_cdevsw, fd->fdu << 6,
+ UID_ROOT, GID_OPERATOR, 0640, "fd%d", fd->fdu);
+ for (i = 0; i < NCLONEDEVS; i++)
+ fd->clonedevs[i] = NODEV;
devstat_add_entry(&fd->device_stats, device_get_name(dev),
device_get_unit(dev), 0, DEVSTAT_NO_ORDERED_TAGS,
DEVSTAT_TYPE_FLOPPY | DEVSTAT_TYPE_IF_OTHER,
@@ -1633,9 +1707,17 @@ static int
fd_detach(device_t dev)
{
struct fd_data *fd;
+ int i;
fd = device_get_softc(dev);
untimeout(fd_turnoff, fd, fd->toffhandle);
+ devstat_remove_entry(&fd->device_stats);
+ destroy_dev(fd->masterdev);
+ for (i = 0; i < NCLONEDEVS; i++)
+ if (fd->clonedevs[i] != NODEV)
+ destroy_dev(fd->clonedevs[i]);
+ cdevsw_remove(&fd_cdevsw);
+ EVENTHANDLER_DEREGISTER(dev_clone, fd->clonetag);
return (0);
}
@@ -1660,10 +1742,13 @@ static driver_t fd_driver = {
DRIVER_MODULE(fd, fdc, fd_driver, fd_devclass, 0, 0);
-/****************************************************************************/
-/* motor control stuff */
-/* remember to not deselect the drive we're working on */
-/****************************************************************************/
+/*
+ * 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)
{
@@ -1673,51 +1758,17 @@ set_motor(struct fdc_data *fdc, int fdsu, int turnon)
DELAY(10);
fdctl_wr(fdc, FDC_DMAE | FDC_MTON);
#else
- int fdout = fdc->fdout;
- int needspecify = 0;
+ int fdout;
- if(turnon) {
+ fdout = fdc->fdout;
+ if (turnon) {
fdout &= ~FDO_FDSEL;
- fdout |= (FDO_MOEN0 << fdsu) + fdsu;
+ fdout |= (FDO_MOEN0 << fdsu) | FDO_FDMAEN | FDO_FRST | fdsu;
} else
fdout &= ~(FDO_MOEN0 << fdsu);
-
- if(!turnon
- && (fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0)
- /* gonna turn off the last drive, put FDC to bed */
- fdout &= ~ (FDO_FRST|FDO_FDMAEN);
- else {
- /* make sure controller is selected and specified */
- if((fdout & (FDO_FRST|FDO_FDMAEN)) == 0)
- needspecify = 1;
- fdout |= (FDO_FRST|FDO_FDMAEN);
- }
-
- fdout_wr(fdc, fdout);
fdc->fdout = fdout;
+ fdout_wr(fdc, fdout);
TRACE1("[0x%x->FDOUT]", fdout);
-
- if (needspecify) {
- /*
- * we silently assume the command will be accepted
- * after an FDC reset
- *
- * Steinbach's Guideline for Systems Programming:
- * Never test for an error condition you don't know
- * how to handle.
- */
-#ifdef PC98
- (void)fd_cmd(fdc, 3, NE7CMD_SPECIFY,
- NE7_SPEC_1(4, 240), NE7_SPEC_2(2, 0),
- 0);
-#else
- (void)fd_cmd(fdc, 3, NE7CMD_SPECIFY,
- NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
- 0);
-#endif
- if (fdc->flags & FDC_HAS_FIFO)
- (void) enable_fifo(fdc);
- }
#endif
}
@@ -1800,7 +1851,7 @@ fdc_reset(fdc_p fdc)
TRACE1("[0x%x->FDOUT]", fdc->fdout);
#endif
- /* after a reset, silently believe the FDC will accept commands */
+ /* XXX after a reset, silently believe the FDC will accept commands */
#ifdef PC98
(void)fd_cmd(fdc, 3, NE7CMD_SPECIFY,
NE7_SPEC_1(4, 240), NE7_SPEC_2(2, 0),
@@ -1814,9 +1865,10 @@ fdc_reset(fdc_p fdc)
(void) enable_fifo(fdc);
}
-/****************************************************************************/
-/* fdc in/out */
-/****************************************************************************/
+/*
+ * FDC IO functions, take care of the main status register, timeout
+ * in case the desired status bits are never set.
+ */
static int
fd_in(struct fdc_data *fdc, int *ptr)
{
@@ -1862,9 +1914,10 @@ out_fdc(struct fdc_data *fdc, int x)
return (0);
}
-/****************************************************************************/
-/* fdopen/fdclose */
-/****************************************************************************/
+/*
+ * Block device driver interface functions (interspersed with even more
+ * auxiliary functions).
+ */
int
Fdopen(dev_t dev, int flags, int mode, struct thread *td)
{
@@ -1954,6 +2007,18 @@ Fdopen(dev_t dev, int flags, int mode, struct thread *td)
#endif
fd->ft = fd_types + type - 1;
fd->flags |= FD_OPEN;
+ /*
+ * 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;
}
@@ -1971,13 +2036,10 @@ fdclose(dev_t dev, int flags, int mode, struct thread *td)
return (0);
}
-/****************************************************************************/
-/* fdstrategy */
-/****************************************************************************/
void
fdstrategy(struct bio *bp)
{
- unsigned nblocks, blknum, cando;
+ long blknum, nblocks;
int s;
fdu_t fdu;
fdc_p fdc;
@@ -1994,10 +2056,9 @@ fdstrategy(struct bio *bp)
bp->bio_error = ENXIO;
bp->bio_flags |= BIO_ERROR;
goto bad;
- };
-
+ }
fdblk = 128 << (fd->ft->secsize);
- if (!(bp->bio_cmd & BIO_FORMAT)) {
+ if (bp->bio_cmd != BIO_FORMAT && bp->bio_cmd != BIO_RDSECTID) {
if (bp->bio_blkno < 0) {
printf(
"fd%d: fdstrat: bad request blkno = %lu, bcount = %ld\n",
@@ -2025,30 +2086,26 @@ fdstrategy(struct bio *bp)
bp->bio_flags |= BIO_ERROR;
goto bad;
}
- blknum = (unsigned) bp->bio_blkno * DEV_BSIZE/fdblk;
+ blknum = bp->bio_blkno * DEV_BSIZE / fdblk;
nblocks = fd->ft->size;
- bp->bio_resid = 0;
- if (blknum + (bp->bio_bcount / fdblk) > nblocks) {
- if (blknum <= nblocks) {
- cando = (nblocks - blknum) * fdblk;
- bp->bio_resid = bp->bio_bcount - cando;
- if (cando == 0)
- goto bad; /* not actually bad but EOF */
- } else {
- bp->bio_error = EINVAL;
- bp->bio_flags |= BIO_ERROR;
- goto bad;
+ if (blknum + bp->bio_bcount / fdblk > nblocks) {
+ if (blknum >= nblocks) {
+ if (bp->bio_cmd == BIO_READ)
+ bp->bio_resid = bp->bio_bcount;
+ else {
+ 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 = bp->bio_blkno;
s = splbio();
bioqdisksort(&fdc->head, bp);
untimeout(fd_turnoff, fd, fd->toffhandle); /* a good idea */
-
- /* Tell devstat we are starting on the transaction */
devstat_start_transaction(&fd->device_stats);
device_busy(fd->dev);
-
fdstart(fdc);
splx(s);
return;
@@ -2057,15 +2114,17 @@ 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 *
-\***************************************************************/
+/*
+ * 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)
{
@@ -2107,7 +2166,7 @@ fd_iotimeout(void *xfdc)
splx(s);
}
-/* just ensure it has the right spl */
+/* Just ensure it has the right spl. */
static void
fd_pseudointr(void *xfdc)
{
@@ -2118,11 +2177,12 @@ fd_pseudointr(void *xfdc)
splx(s);
}
-/***********************************************************************\
-* fdintr *
-* keep calling the state machine until it returns a 0 *
-* ALWAYS called at SPLBIO *
-\***********************************************************************/
+/*
+ * fdc_intr
+ *
+ * Keep calling the state machine until it returns a 0.
+ * Always called at splbio.
+ */
static void
fdc_intr(void *xfdc)
{
@@ -2132,8 +2192,8 @@ fdc_intr(void *xfdc)
}
/*
- * magic pseudo-DMA initialization for YE FDC. Sets count and
- * direction
+ * 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, \
@@ -2142,9 +2202,10 @@ fdc_intr(void *xfdc)
((wr ? 0x80 : 0) | ((((cnt)-1) >> 8) & 0x7f)));
/*
- * fdcpio(): perform programmed IO read/write for YE PCMCIA floppy
+ * fdcpio(): perform programmed IO read/write for YE PCMCIA floppy.
*/
-static int fdcpio(fdc_p fdc, long flags, caddr_t addr, u_int count)
+static int
+fdcpio(fdc_p fdc, long flags, caddr_t addr, u_int count)
{
u_char *cptr = (u_char *)addr;
@@ -2152,7 +2213,7 @@ static int fdcpio(fdc_p fdc, long flags, caddr_t addr, u_int count)
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);
@@ -2160,19 +2221,22 @@ static int fdcpio(fdc_p fdc, long flags, caddr_t addr, u_int count)
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);
}
-/***********************************************************************\
-* The controller state machine. *
-* if it returns a non zero value, it should be called again immediatly *
-\***********************************************************************/
+/*
+ * The controller state machine.
+ *
+ * If it returns a non zero value, it should be called again immediately.
+ */
static int
fdstate(fdc_p fdc)
{
- int read, format, head, i, sec = 0, sectrac, st0, cyl, st3, idf;
- unsigned blknum = 0, b_cylinder = 0;
+ struct fdc_readid *idp;
+ int read, format, rdsectid, cylinder, head, i, sec = 0, sectrac;
+ int st0, cyl, st3, idf;
+ unsigned long blknum;
fdu_t fdu = fdc->fdu;
fd_p fd;
register struct bio *bp;
@@ -2188,10 +2252,10 @@ fdstate(fdc_p fdc)
}
}
if (bp == NULL) {
- /***********************************************\
- * nothing left for this controller to do *
- * Force into the IDLE state, *
- \***********************************************/
+ /*
+ * Nothing left for this controller to do,
+ * force into the IDLE state.
+ */
fdc->state = DEVIDLE;
if (fdc->fd) {
device_printf(fdc->fdc_dev,
@@ -2212,17 +2276,10 @@ fdstate(fdc_p fdc)
idf = ISADMA_READ;
else
idf = ISADMA_WRITE;
- format = bp->bio_cmd & BIO_FORMAT;
- if (format) {
+ format = bp->bio_cmd == BIO_FORMAT;
+ rdsectid = bp->bio_cmd == BIO_RDSECTID;
+ if (format)
finfo = (struct fd_formb *)bp->bio_data;
- fd->skip = (char *)&(finfo->fd_formb_cylno(0))
- - (char *)finfo;
- }
- if (fdc->state == DOSEEK || fdc->state == SEEKCOMPLETE) {
- blknum = (unsigned) bp->bio_pblkno * DEV_BSIZE/fdblk +
- fd->skip/fdblk;
- b_cylinder = blknum / (fd->ft->sectrac * fd->ft->heads);
- }
TRACE1("fd%d", fdu);
TRACE1("[%s]", fdstates[fdc->state]);
TRACE1("(0x%x)", fd->flags);
@@ -2263,17 +2320,17 @@ fdstate(fdc_p fdc)
fdc->fdctl_wr(fdc, fd->ft->trans);
#endif
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 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); /* come back later */
+ return (0); /* will return later */
}
- /*******************************************************\
- * Maybe if it's not starting, it SHOULD be starting *
- \*******************************************************/
+ /*
+ * Maybe if it's not starting, it SHOULD be starting.
+ */
#ifdef EPSON_NRDISK
if (fdu != nrdu) {
if (!(fd->flags & FD_MOTOR))
@@ -2292,7 +2349,7 @@ fdstate(fdc_p fdc)
{
fdc->state = MOTORWAIT;
fd_turnon(fd);
- return (0);
+ return (0); /* will return later */
}
else /* at least make sure we are selected */
{
@@ -2304,22 +2361,29 @@ fdstate(fdc_p fdc)
fdc->flags &= ~FDC_NEEDS_RESET;
} else
fdc->state = DOSEEK;
- break;
+ return (1); /* will return immediately */
+
case DOSEEK:
- if (b_cylinder == (unsigned)fd->track)
+#ifdef PC98
+ blknum = bp->bio_pblkno * DEV_BSIZE / fdblk + fd->skip / fdblk;
+#else
+ blknum = bp->bio_pblkno + fd->skip / fdblk;
+#endif
+ cylinder = blknum / (fd->ft->sectrac * fd->ft->heads);
+ if (cylinder == fd->track)
{
fdc->state = SEEKCOMPLETE;
- break;
+ return (1); /* will return immediately */
}
#ifdef PC98
pc98_fd_check_ready(fdu);
#endif
if (fd_cmd(fdc, 3, NE7CMD_SEEK,
- fd->fdsu, b_cylinder * fd->ft->steptrac,
+ fd->fdsu, cylinder * fd->ft->steptrac,
0))
{
/*
- * seek command not accepted, looks like
+ * Seek command not accepted, looks like
* the FDC went off to the Saints...
*/
fdc->retry = 6; /* try a reset */
@@ -2328,15 +2392,24 @@ fdstate(fdc_p 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 */
- /* Make sure seek really happened*/
+
+ case SEEKCOMPLETE : /* seek done, start DMA */
+#ifdef PC98
+ blknum = bp->bio_pblkno * DEV_BSIZE / fdblk + fd->skip / fdblk;
+#else
+ blknum = bp->bio_pblkno + fd->skip / fdblk;
+#endif
+ cylinder = blknum / (fd->ft->sectrac * fd->ft->heads);
+
+ /* Make sure seek really happened. */
if(fd->track == FD_NO_TRACK) {
- int descyl = b_cylinder * fd->ft->steptrac;
+ int descyl = cylinder * fd->ft->steptrac;
do {
/*
* This might be a "ready changed" interrupt,
@@ -2361,10 +2434,10 @@ fdstate(fdc_p fdc)
*/
if (fd_sense_int(fdc, &st0, &cyl)
== FD_NOT_VALID)
- return 0;
+ 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 */
+ return (0); /* hope for a real intr */
} while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
if (0 == descyl) {
@@ -2405,20 +2478,28 @@ fdstate(fdc_p fdc)
}
}
- fd->track = b_cylinder;
+ fd->track = cylinder;
+ if (format)
+ fd->skip = (char *)&(finfo->fd_formb_cylno(0))
+ - (char *)finfo;
#ifdef EPSON_NRDISK
if (fdu != nrdu) {
#endif /* EPSON_NRDISK */
- if (!(fdc->flags & FDC_NODMA))
+ if (!rdsectid && !(fdc->flags & FDC_NODMA))
isa_dmastart(idf, bp->bio_data+fd->skip,
format ? bp->bio_bcount : fdblk, fdc->dmachan);
+#ifdef PC98
+ blknum = bp->bio_pblkno * DEV_BSIZE / fdblk + fd->skip / fdblk;
+#else
+ blknum = bp->bio_pblkno + fd->skip / fdblk;
+#endif
sectrac = fd->ft->sectrac;
sec = blknum % (sectrac * fd->ft->heads);
head = sec / sectrac;
sec = sec % sectrac + 1;
fd->hddrv = ((head&1)<<2)+fdu;
- if(format || !read)
+ if(format || !(read || rdsectid))
{
/* make sure the drive is writable */
if(fd_sense_drive_status(fdc, &st3) != 0)
@@ -2449,7 +2530,7 @@ fdstate(fdc_p fdc)
fdc->status[5] = sec;
fdc->retry = 8; /* break out immediately */
fdc->state = IOTIMEDOUT; /* not really... */
- return (1);
+ return (1); /* will return immediately */
}
}
@@ -2489,17 +2570,24 @@ fdstate(fdc_p fdc)
fdc->retry = 6;
return (retrier(fdc));
}
+ } else if (rdsectid) {
+ if (fd_cmd(fdc, 2, NE7CMD_READID, head << 2 | fdu, 0)) {
+ /* controller jamming */
+ fdc->retry = 6;
+ return (retrier(fdc));
+ }
} else {
+ /* read or write operation */
if (fdc->flags & FDC_NODMA) {
/*
- * this seems to be necessary even when
- * reading data
+ * 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
+ * Perform the write pseudo-DMA before
+ * the WRITE command is sent.
*/
if (!read)
(void)fdcpio(fdc,bp->bio_cmd,
@@ -2527,20 +2615,20 @@ fdstate(fdc_p fdc)
return (retrier(fdc));
}
}
- if (fdc->flags & FDC_NODMA)
+ if (!rdsectid && (fdc->flags & FDC_NODMA))
/*
- * if this is a read, then simply await interrupt
- * before performing PIO
+ * 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
+ * Write (or format) operation will fall through and
+ * await completion interrupt.
*/
fdc->state = IOCOMPLETE;
fd->tohandle = timeout(fd_iotimeout, fdc, hz);
@@ -2575,15 +2663,16 @@ fdstate(fdc_p fdc)
fdc->state = IOCOMPLETE;
}
#endif
+
case PIOREAD:
/*
- * actually perform the PIO read. The IOCOMPLETE case
- * removes the timeout for us.
+ * 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 */
+ case IOCOMPLETE: /* IO done, post-analyze */
#ifdef EPSON_NRDISK
if (fdu != nrdu)
untimeout(fd_iotimeout, fdc, fd->tohandle);
@@ -2591,8 +2680,8 @@ fdstate(fdc_p fdc)
untimeout(fd_iotimeout, fdc, fd->tohandle);
#endif
- if (fd_read_status(fdc, fd->fdsu)) {
- if (!(fdc->flags & FDC_NODMA))
+ 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);
@@ -2604,12 +2693,11 @@ fdstate(fdc_p fdc)
fdc->state = IOTIMEDOUT;
/* FALLTHROUGH */
-
case IOTIMEDOUT:
#ifdef EPSON_NRDISK
if (fdu != nrdu) {
#endif /* EPSON_NRDISK */
- if (!(fdc->flags & FDC_NODMA))
+ if (!rdsectid && !(fdc->flags & FDC_NODMA))
isa_dmadone(idf, bp->bio_data + fd->skip,
format ? bp->bio_bcount : fdblk, fdc->dmachan);
#ifdef EPSON_NRDISK
@@ -2620,16 +2708,23 @@ fdstate(fdc_p fdc)
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.
- * Just restart it, don't increment retry
- * count. (vak)
- */
- fdc->state = SEEKCOMPLETE;
- return (1);
+ * 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 */
}
- else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_IV
+ 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
@@ -2639,13 +2734,24 @@ fdstate(fdc_p fdc)
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 (!format && fd->skip < bp->bio_bcount - bp->bio_resid) {
+ 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);
@@ -2653,12 +2759,14 @@ fdstate(fdc_p fdc)
fdc->fdu = -1;
fdc->state = FINDWORK;
}
- return (1);
+ return (1); /* will return immediately */
+
case RESETCTLR:
fdc_reset(fdc);
fdc->retry++;
fdc->state = RESETCOMPLETE;
- return (0);
+ return (0); /* will return later */
+
case RESETCOMPLETE:
/*
* Discard all the results from the reset so that they
@@ -2667,7 +2775,7 @@ fdstate(fdc_p fdc)
for (i = 0; i < 4; i++)
(void)fd_sense_int(fdc, &st0, &cyl);
fdc->state = STARTRECAL;
- /* Fall through. */
+ /* FALLTHROUGH */
case STARTRECAL:
#ifdef PC98
pc98_fd_check_ready(fdu);
@@ -2679,21 +2787,23 @@ fdstate(fdc_p 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;
+ 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 */
+ return (0); /* hope for a real intr */
} while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
#ifdef EPSON_NRDISK
if (fdu == nrdu) {
@@ -2705,12 +2815,12 @@ fdstate(fdc_p fdc)
{
if(fdc->retry > 3)
/*
- * a recalibrate from beyond cylinder 77
+ * 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
+ * time in a line.
*/
printf("fd%d: recal failed ST0 %b cyl %d\n",
fdu, st0, NE7_ST0BITS, cyl);
@@ -2720,7 +2830,8 @@ fdstate(fdc_p fdc)
fd->track = 0;
/* Seek (probably) necessary */
fdc->state = DOSEEK;
- return (1); /* will return immediatly */
+ return (1); /* will return immediately */
+
case MOTORWAIT:
if(fd->flags & FD_MOTOR_WAIT)
{
@@ -2729,19 +2840,13 @@ fdstate(fdc_p fdc)
if (fdc->flags & FDC_NEEDS_RESET) {
fdc->state = RESETCTLR;
fdc->flags &= ~FDC_NEEDS_RESET;
- } else {
- /*
- * If all motors were off, then the controller was
- * reset, so it has lost track of the current
- * cylinder. Recalibrate to handle this case.
- * But first, discard the results of the reset.
- */
- fdc->state = RESETCOMPLETE;
- }
- return (1); /* will return immediatly */
+ } else
+ fdc->state = DOSEEK;
+ return (1); /* will return immediately */
+
default:
device_printf(fdc->fdc_dev, "unexpected FD int->");
- if (fd_read_status(fdc, fd->fdsu) == 0)
+ if (fd_read_status(fdc) == 0)
printf("FDC status :%x %x %x %x %x %x %x ",
fdc->status[0],
fdc->status[1],
@@ -2755,13 +2860,12 @@ fdstate(fdc_p fdc)
if (fd_sense_int(fdc, &st0, &cyl) != 0)
{
printf("[controller is dead now]\n");
- return (0);
+ return (0); /* will return later */
}
printf("ST0 = %x, PCN = %x\n", st0, cyl);
- return (0);
+ return (0); /* will return later */
}
- /*XXX confusing: some branches return immediately, others end up here*/
- return (1); /* Come back immediatly to new state */
+ /* noone should ever get here */
}
static int
@@ -2793,32 +2897,27 @@ retrier(struct fdc_data *fdc)
break;
default:
fail:
- {
- int printerror = (fd->options & FDOPT_NOERRLOG) == 0;
-
- if (printerror)
- diskerr(bp, "hard error", fdc->fd->skip / DEV_BSIZE,
- (struct disklabel *)NULL);
- if (printerror) {
- 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_NOERRLOG) == 0) {
+ diskerr(bp, "hard error", fdc->fd->skip / DEV_BSIZE,
+ (struct disklabel *)NULL);
+ 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;
- }
+ 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);
@@ -2840,150 +2939,132 @@ fdbiodone(struct bio *bp)
}
static int
-fdformat(dev, finfo, td)
- dev_t dev;
- struct fd_formb *finfo;
- struct thread *td;
+fdmisccmd(dev_t dev, u_int cmd, void *data)
{
- struct proc *p = td->td_proc;
- fdu_t fdu;
- fd_p fd;
-
+ fdu_t fdu;
+ fd_p fd;
struct bio *bp;
- int rv = 0, s;
+ struct fd_formb *finfo;
+ struct fdc_readid *idfield;
size_t fdblk;
- fdu = FDUNIT(minor(dev));
- fd = devclass_get_softc(fd_devclass, fdu);
+ fdu = FDUNIT(minor(dev));
+ fd = devclass_get_softc(fd_devclass, fdu);
fdblk = 128 << fd->ft->secsize;
+ finfo = (struct fd_formb *)data;
+ idfield = (struct fdc_readid *)data;
- /* set up a buffer header for fdstrategy() */
- bp = (struct bio *)malloc(sizeof(struct bio), M_TEMP, M_NOWAIT);
- if(bp == 0)
- return ENOMEM;
- /*
- * keep the process from being swapped
- */
- PHOLD(p);
- bzero((void *)bp, sizeof(*bp));
- bp->bio_cmd = BIO_FORMAT;
+ bp = malloc(sizeof(struct bio), M_TEMP, M_ZERO);
/*
- * calculate a fake blkno, so fdstrategy() would initiate a
- * seek to the requested cylinder
+ * Set up a bio request for fdstrategy(). bio_blkno is faked
+ * so that fdstrategy() will seek to the the requested
+ * cylinder, and use the desired head. Since we are not
+ * interested in bioqdisksort() munging with our faked bio
+ * request, we mark it as being an ordered request.
*/
- bp->bio_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads)
- + finfo->head * fd->ft->sectrac) * fdblk / DEV_BSIZE;
-
- bp->bio_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
- bp->bio_data = (caddr_t)finfo;
-
- /* now do the format */
+ bp->bio_cmd = cmd;
+ if (cmd == BIO_FORMAT) {
+ bp->bio_blkno =
+ (finfo->cyl * (fd->ft->sectrac * fd->ft->heads) +
+ finfo->head * fd->ft->sectrac) *
+ fdblk / DEV_BSIZE;
+ bp->bio_bcount = sizeof(struct fd_idfield_data) *
+ finfo->fd_formb_nsecs;
+ } else if (cmd == BIO_RDSECTID) {
+ bp->bio_blkno =
+ (idfield->cyl * (fd->ft->sectrac * fd->ft->heads) +
+ idfield->head * fd->ft->sectrac) *
+ fdblk / DEV_BSIZE;
+ 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;
- fdstrategy(bp);
+ bp->bio_flags = BIO_ORDERED;
- /* ...and wait for it to complete */
- s = splbio();
- while(!(bp->bio_flags & BIO_DONE)) {
- rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
- if (rv == EWOULDBLOCK)
- break;
- }
- splx(s);
-
- if (rv == EWOULDBLOCK) {
- /* timed out */
- rv = EIO;
- device_unbusy(fd->dev);
- }
- if (bp->bio_flags & BIO_ERROR)
- rv = bp->bio_error;
/*
- * allow the process to be swapped
+ * Now run the command. The wait loop is a version of bufwait()
+ * adapted for struct bio instead of struct buf and specialized
+ * for the current context.
*/
- PRELE(p);
+ fdstrategy(bp);
+ while ((bp->bio_flags & BIO_DONE) == 0)
+ tsleep(bp, PRIBIO, "fdcmd", 0);
+
free(bp, M_TEMP);
- return rv;
+ return (bp->bio_flags & BIO_ERROR ? bp->bio_error : 0);
}
-/*
- * TODO: don't allocate buffer on stack.
- */
-
static int
-fdioctl(dev, cmd, addr, flag, td)
- dev_t dev;
- u_long cmd;
- caddr_t addr;
- int flag;
- struct thread *td;
+fdioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
{
- fdu_t fdu = FDUNIT(minor(dev));
- fd_p fd = devclass_get_softc(fd_devclass, fdu);
- size_t fdblk;
-
+ fdu_t fdu;
+ fd_p fd;
struct fd_type *fdt;
- struct disklabel *dl;
+ struct disklabel *lp;
struct fdc_status *fsp;
- char buffer[DEV_BSIZE];
- int error = 0;
+ struct fdc_readid *rid;
+ size_t fdblk;
+ int error;
- fdblk = 128 << fd->ft->secsize;
+ fdu = FDUNIT(minor(dev));
+ fd = devclass_get_softc(fd_devclass, fdu);
#ifdef PC98
pc98_fd_check_ready(fdu);
#endif
+
+ fdblk = 128 << fd->ft->secsize;
+ error = 0;
+
switch (cmd) {
case DIOCGDINFO:
- bzero(buffer, sizeof (buffer));
- dl = (struct disklabel *)buffer;
- dl->d_secsize = fdblk;
+ lp = malloc(sizeof(*lp), M_TEMP, M_ZERO);
+ lp->d_secsize = fdblk;
fdt = fd->ft;
- dl->d_secpercyl = fdt->size / fdt->tracks;
- dl->d_type = DTYPE_FLOPPY;
-
- if (readdisklabel(dkmodpart(dev, RAW_PART), dl)
- == NULL)
- error = 0;
- else
+ lp->d_secpercyl = fdt->size / fdt->tracks;
+ lp->d_type = DTYPE_FLOPPY;
+ if (readdisklabel(dkmodpart(dev, RAW_PART), lp) != NULL)
error = EINVAL;
-
- *(struct disklabel *)addr = *dl;
+ else
+ *(struct disklabel *)addr = *lp;
+ free(lp, M_TEMP);
break;
case DIOCSDINFO:
if ((flag & FWRITE) == 0)
- error = EBADF;
+ return (EBADF);
+ /*
+ * XXX perhaps should call setdisklabel() to do error checking
+ * although there is nowhere to "set" the result. Perhaps
+ * should always just fail.
+ */
break;
case DIOCWLABEL:
if ((flag & FWRITE) == 0)
- error = EBADF;
+ return (EBADF);
break;
case DIOCWDINFO:
- if ((flag & FWRITE) == 0) {
- error = EBADF;
- break;
- }
-
- dl = (struct disklabel *)addr;
-
- if ((error = setdisklabel((struct disklabel *)buffer, dl,
- (u_long)0)) != 0)
- break;
-
- error = writedisklabel(dev, (struct disklabel *)buffer);
+ if ((flag & FWRITE) == 0)
+ return (EBADF);
+ lp = malloc(DEV_BSIZE, M_TEMP, M_ZERO);
+ error = setdisklabel(lp, (struct disklabel *)addr, (u_long)0);
+ if (error != 0)
+ error = writedisklabel(dev, lp);
+ free(lp, M_TEMP);
break;
+
case FD_FORM:
if ((flag & FWRITE) == 0)
- error = EBADF; /* must be opened for writing */
- else if (((struct fd_formb *)addr)->format_version !=
- FD_FORMAT_VERSION)
- error = EINVAL; /* wrong version of formatting prog */
- else
- error = fdformat(dev, (struct fd_formb *)addr, td);
+ 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, BIO_FORMAT, addr);
break;
case FD_GTYPE: /* get drive type */
@@ -2993,7 +3074,7 @@ fdioctl(dev, cmd, addr, flag, td)
case FD_STYPE: /* set drive type */
/* this is considered harmful; only allow for superuser */
if (suser_td(td) != 0)
- return EPERM;
+ return (EPERM);
*fd->ft = *(struct fd_type *)addr;
break;
@@ -3005,39 +3086,39 @@ fdioctl(dev, cmd, addr, flag, td)
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(td) != 0)
- return EPERM;
+ 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;
+ 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, BIO_RDSECTID, addr);
+ break;
+
default:
error = ENOTTY;
break;
}
return (error);
}
-
-/*
- * Hello emacs, these are the
- * Local Variables:
- * c-indent-level: 8
- * c-continued-statement-offset: 8
- * c-continued-brace-offset: 0
- * c-brace-offset: -8
- * c-brace-imaginary-offset: 0
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c++-hanging-braces: 1
- * c++-access-specifier-offset: -8
- * c++-empty-arglist-indent: 8
- * c++-friend-offset: 0
- * End:
- */
OpenPOWER on IntegriCloud