aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/fdc
diff options
context:
space:
mode:
authorJung-uk Kim <jkim@FreeBSD.org>2008-11-15 01:43:34 +0000
committerJung-uk Kim <jkim@FreeBSD.org>2008-11-15 01:43:34 +0000
commitc884498f0bde4c8a8b7924a4a9fe63d561a8c7d5 (patch)
treee3a1c76c7b0e35f54e3fe26be216a2c2708664a4 /sys/dev/fdc
parent4254ef5903398d567a01115cf3b5153788048cb2 (diff)
downloadsrc-c884498f0bde4c8a8b7924a4a9fe63d561a8c7d5.tar.gz
src-c884498f0bde4c8a8b7924a4a9fe63d561a8c7d5.zip
- Revive fdc(4) per-device flag 0x10, which was removed in r1.284[1].
- If the flag is set and auto-select fails, assume disk is not present. - Set disk empty flag only when the floppy controller reset is needed. It fixes regression introduced in r1.311, which prevented it from ignoring errors. Now fdformat(1) and dd(1) with conv=noerror option can continue when read/write errors occur as they should. - Do not retry disk probing as it is extremely slow and pointless. - Move the disk probing code into a separate function. - Do not reset disk empty flag if write-protect check fails somehow. PR: kern/116538[1]
Notes
Notes: svn path=/head/; revision=184976
Diffstat (limited to 'sys/dev/fdc')
-rw-r--r--sys/dev/fdc/fdc.c149
1 files changed, 86 insertions, 63 deletions
diff --git a/sys/dev/fdc/fdc.c b/sys/dev/fdc/fdc.c
index bcdfcb9067a3..08b7897f8e7a 100644
--- a/sys/dev/fdc/fdc.c
+++ b/sys/dev/fdc/fdc.c
@@ -97,6 +97,8 @@ __FBSDID("$FreeBSD$");
* fd_drivetype; on i386 machines, if
* given as 0, use RTC type for fd0
* and fd1 */
+#define FD_NO_CHLINE 0x10 /* drive does not support changeline
+ * aka. unit attention */
#define FD_NO_PROBE 0x20 /* don't probe drive (seek test), just
* assume it is there */
@@ -263,6 +265,7 @@ struct fd_data {
static driver_intr_t fdc_intr;
static driver_filter_t fdc_intr_fast;
static void fdc_reset(struct fdc_data *);
+static int fd_probe_disk(struct fd_data *, int *);
SYSCTL_NODE(_debug, OID_AUTO, fdc, CTLFLAG_RW, 0, "fdc driver");
@@ -768,9 +771,11 @@ fdc_worker(struct fdc_data *fdc)
(fdc->retry >= retries || (fd->options & FDOPT_NORETRY))) {
if ((debugflags & 4))
printf("Too many retries (EIO)\n");
- mtx_lock(&fdc->fdc_mtx);
- fd->flags |= FD_EMPTY;
- mtx_unlock(&fdc->fdc_mtx);
+ if (fdc->flags & FDC_NEEDS_RESET) {
+ mtx_lock(&fdc->fdc_mtx);
+ fd->flags |= FD_EMPTY;
+ mtx_unlock(&fdc->fdc_mtx);
+ }
return (fdc_biodone(fdc, EIO));
}
@@ -836,65 +841,12 @@ fdc_worker(struct fdc_data *fdc)
fdctl_wr(fdc, fd->ft->trans);
if (bp->bio_cmd & BIO_PROBE) {
-
- if (!(fdin_rd(fdc) & FDI_DCHG) && !(fd->flags & FD_EMPTY))
+ if ((!(device_get_flags(fd->dev) & FD_NO_CHLINE) &&
+ !(fdin_rd(fdc) & FDI_DCHG) &&
+ !(fd->flags & FD_EMPTY)) ||
+ fd_probe_disk(fd, &need_recal) == 0)
return (fdc_biodone(fdc, 0));
-
- /*
- * Try to find out if we have a disk in the drive
- *
- * First recal, then seek to cyl#1, this clears the
- * old condition on the disk change line so we can
- * examine it for current status
- */
- if (debugflags & 0x40)
- printf("New disk in probe\n");
- mtx_lock(&fdc->fdc_mtx);
- fd->flags |= FD_NEWDISK;
- mtx_unlock(&fdc->fdc_mtx);
- retry_line = __LINE__;
- if (fdc_cmd(fdc, 2, NE7CMD_RECAL, fd->fdsu, 0))
- return (1);
- tsleep(fdc, PRIBIO, "fdrecal", hz);
- retry_line = __LINE__;
- if (fdc_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID)
- return (1); /* XXX */
- retry_line = __LINE__;
- if ((st0 & 0xc0) || cyl != 0)
- return (1);
-
- /* Seek to track 1 */
- retry_line = __LINE__;
- if (fdc_cmd(fdc, 3, NE7CMD_SEEK, fd->fdsu, 1, 0))
- return (1);
- tsleep(fdc, PRIBIO, "fdseek", hz);
- retry_line = __LINE__;
- if (fdc_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID)
- return (1); /* XXX */
- need_recal |= (1 << fd->fdsu);
- if (fdin_rd(fdc) & FDI_DCHG) {
- if (debugflags & 0x40)
- printf("Empty in probe\n");
- mtx_lock(&fdc->fdc_mtx);
- fd->flags |= FD_EMPTY;
- mtx_unlock(&fdc->fdc_mtx);
- } else {
- if (debugflags & 0x40)
- printf("Got disk in probe\n");
- mtx_lock(&fdc->fdc_mtx);
- fd->flags &= ~FD_EMPTY;
- mtx_unlock(&fdc->fdc_mtx);
- retry_line = __LINE__;
- if(fdc_sense_drive(fdc, &st3) != 0)
- return (1);
- mtx_lock(&fdc->fdc_mtx);
- if(st3 & NE7_ST3_WP)
- fd->flags |= FD_WP;
- else
- fd->flags &= ~FD_WP;
- mtx_unlock(&fdc->fdc_mtx);
- }
- return (fdc_biodone(fdc, 0));
+ return (1);
}
/*
@@ -1238,6 +1190,71 @@ fd_enqueue(struct fd_data *fd, struct bio *bp)
mtx_unlock(&fdc->fdc_mtx);
}
+/*
+ * Try to find out if we have a disk in the drive.
+ */
+static int
+fd_probe_disk(struct fd_data *fd, int *recal)
+{
+ struct fdc_data *fdc;
+ int st0, st3, cyl;
+ int oopts, ret;
+
+ fdc = fd->fdc;
+ oopts = fd->options;
+ fd->options |= FDOPT_NOERRLOG | FDOPT_NORETRY;
+ ret = 1;
+
+ /*
+ * First recal, then seek to cyl#1, this clears the old condition on
+ * the disk change line so we can examine it for current status.
+ */
+ if (debugflags & 0x40)
+ printf("New disk in probe\n");
+ mtx_lock(&fdc->fdc_mtx);
+ fd->flags |= FD_NEWDISK;
+ mtx_unlock(&fdc->fdc_mtx);
+ if (fdc_cmd(fdc, 2, NE7CMD_RECAL, fd->fdsu, 0))
+ goto done;
+ tsleep(fdc, PRIBIO, "fdrecal", hz);
+ if (fdc_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID)
+ goto done; /* XXX */
+ if ((st0 & 0xc0) || cyl != 0)
+ goto done;
+
+ /* Seek to track 1 */
+ if (fdc_cmd(fdc, 3, NE7CMD_SEEK, fd->fdsu, 1, 0))
+ goto done;
+ tsleep(fdc, PRIBIO, "fdseek", hz);
+ if (fdc_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID)
+ goto done; /* XXX */
+ *recal |= (1 << fd->fdsu);
+ if (fdin_rd(fdc) & FDI_DCHG) {
+ if (debugflags & 0x40)
+ printf("Empty in probe\n");
+ mtx_lock(&fdc->fdc_mtx);
+ fd->flags |= FD_EMPTY;
+ mtx_unlock(&fdc->fdc_mtx);
+ } else {
+ if (fdc_sense_drive(fdc, &st3) != 0)
+ goto done;
+ if (debugflags & 0x40)
+ printf("Got disk in probe\n");
+ mtx_lock(&fdc->fdc_mtx);
+ fd->flags &= ~FD_EMPTY;
+ if (st3 & NE7_ST3_WP)
+ fd->flags |= FD_WP;
+ else
+ fd->flags &= ~FD_WP;
+ mtx_unlock(&fdc->fdc_mtx);
+ }
+ ret = 0;
+
+done:
+ fd->options = oopts;
+ return (ret);
+}
+
static int
fdmisccmd(struct fd_data *fd, u_int cmd, void *data)
{
@@ -1350,7 +1367,7 @@ fdautoselect(struct fd_data *fd)
if (debugflags & 0x40)
device_printf(fd->dev, "autoselection failed\n");
fdsettype(fd, fd_native_types[fd->type]);
- return (0);
+ return (-1);
} else {
if (debugflags & 0x40) {
device_printf(fd->dev,
@@ -1411,7 +1428,13 @@ fd_access(struct g_provider *pp, int r, int w, int e)
if (fd->flags & FD_EMPTY)
return (ENXIO);
if (fd->flags & FD_NEWDISK) {
- fdautoselect(fd);
+ if (fdautoselect(fd) != 0 &&
+ (device_get_flags(fd->dev) & FD_NO_CHLINE)) {
+ mtx_lock(&fdc->fdc_mtx);
+ fd->flags |= FD_EMPTY;
+ mtx_unlock(&fdc->fdc_mtx);
+ return (ENXIO);
+ }
mtx_lock(&fdc->fdc_mtx);
fd->flags &= ~FD_NEWDISK;
mtx_unlock(&fdc->fdc_mtx);