Author: jkim
Date: Sat Nov 15 01:43:34 2008
New Revision: 184976
URL: http://svn.freebsd.org/changeset/base/184976

Log:
  - 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]

Modified:
  head/sys/dev/fdc/fdc.c

Modified: head/sys/dev/fdc/fdc.c
==============================================================================
--- head/sys/dev/fdc/fdc.c      Fri Nov 14 23:32:31 2008        (r184975)
+++ head/sys/dev/fdc/fdc.c      Sat Nov 15 01:43:34 2008        (r184976)
@@ -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 bi
        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, 
                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);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to