kernel: Make floppies work again.
authorzrj <rimvydas.jasinskas@gmail.com>
Tue, 28 Nov 2017 11:44:44 +0000 (13:44 +0200)
committerzrj <zrj@dragonflybsd.org>
Wed, 29 Nov 2017 16:20:25 +0000 (18:20 +0200)
Revive the old x86 32bit only fdc(4) driver, it only needs just a few changes.
The fdc was never ported to work on x86_64 DragonFly, so rather than remove it
together with its manpage, fix few things and hook it to LINT64 config so that
we would keep track the state of it and not keep it in a dusty corner of sys/.

On modern x86_64 systems fdc($) has little value and it is getting harder and
harder to find floppy drives that work or even the motherboards that still have
the FDD headers to hook the 34pin ribbon cable, but I feel nostalgic about the
scratching noises the floppy drive makes while performing the operations.
So went through all storage closets and find one that works, blew out all the
accumulated dusts, cleaned the magnetic heads with a folder paper tissue good.
The hardest part was to find a floppy disk. Only could find just a single one
stashed away deep on the floor of a very old safe under heeps of old documents.

For fdc(4) to actually work, some adjustmens to isa_dma.c were needed because
of how ISA bus probing is done in platform/pc64/x86_64/autoconf.c. To work
around the exhaustion of low DMA memory before it gets to isa_probe_children()
now try to preallocate contiguous buffer of 512KB and free it just before the
probe of ISA bus. This should help any legacy ISA drivers(including ppc(4))
or even some of more picky drivers that are not built in into the kernel.

For case where isa_dmainit() would still fail to allocate the buffer fitting
the requirements, have added the safety checks and explicit fallback to non
DMA mode by setting the FDC_NODMA flag to avoid panics on "bad bounce buffer".
Floppy drive would not work properly, but it is this versus a panic. There are
other issues too. For some reason some files tend to be read with stripes of
zeros, but write operations seems to work. Same floppy is readable on linux.

Currently can not debug the issue cause my floppy had seen better days:
_# time dd if=/dev/fd0 of=/tmp/recover.img conv=sync,noerror
...
dd: /dev/fd0: Input/output error
2880+0 records in
2880+0 records out
1474560 bytes transferred in 80.723953 secs (18267 bytes/sec)

while dmesg:
fd0: hard error reading offset 00000000ae00 for 512 (ST0 40<abnrml> ST1 20<bad_crc> ST2 20<bad_crc> cyl 2 hd 0 sec 16)
fd0: hard error reading offset 00000000f600 for 512 (ST0 40<abnrml> ST1 1<no_am> ST2 1<no_dam> cyl 3 hd 0 sec 16)
fd0: hard error reading offset 000000113800 for 512 (ST0 40<abnrml> ST1 20<bad_crc> ST2 20<bad_crc> cyl 61 hd 0 sec 9)
fd0: hard error reading offset 000000115c00 for 512 (ST0 44<abnrml,top_head> ST1 4<sec_not_fnd> ST2 10<wrong_cyl> cyl 61 hd 1 sec 9)
fd0: hard error reading offset 00000011a400 for 512 (ST0 44<abnrml,top_head> ST1 4<sec_not_fnd> ST2 0 cyl 62 hd 1 sec 9)
fd0: hard error reading offset 00000011ec00 for 512 (ST0 44<abnrml,top_head> ST1 4<sec_not_fnd> ST2 0 cyl 63 hd 1 sec 9)
fd0: hard error reading offset 000000123400 for 512 (ST0 44<abnrml,top_head> ST1 4<sec_not_fnd> ST2 0 cyl 64 hd 1 sec 9)
fd0: hard error reading offset 000000127c00 for 512 (ST0 44<abnrml,top_head> ST1 4<sec_not_fnd> ST2 0 cyl 65 hd 1 sec 9)

Given the state of my single floppy I cannot even do a proper newfs_msdos(8).
So maybe someone who has a collection of good floppies could give it a go.

While there, hook old musycc(4) driver to LINT64, it was fixed in:
906779c3d1e064e55bb019342ad6c1621cc04399

sys/bus/isa/isavar.h
sys/bus/isa/x86_64/isa_dma.c
sys/conf/files
sys/config/LINT64
sys/dev/disk/fd/fd.c
sys/dev/disk/fd/fdc.h
sys/platform/pc64/x86_64/autoconf.c
sys/vm/vm_page.c

index fb54f12..f1873da 100644 (file)
@@ -164,7 +164,7 @@ extern void isa_probe_children(device_t dev);
 
 extern void    isa_dmacascade (int chan);
 extern void    isa_dmadone (int flags, caddr_t addr, int nbytes, int chan);
-extern void    isa_dmainit (int chan, u_int bouncebufsize);
+extern int     isa_dma_init (int chan, u_int bouncebufsize, int flags);
 extern void    isa_dmastart (int flags, caddr_t addr, u_int nbytes, int chan);
 extern int     isa_dma_acquire (int chan);
 extern void    isa_dma_release (int chan);
@@ -174,6 +174,12 @@ unsigned isa_dmabp (struct buf *);
 
 int isab_attach(device_t dev);
 
+#define isa_dmainit(chan, size) do {                                   \
+       if (isa_dma_init(chan, size, M_NOWAIT))                         \
+               kprintf("WARNING: isa_dma_init(%d, %ju) failed\n",      \
+                       (int)(chan), (uintmax_t)(size));                \
+       } while (0)
+
 #endif /* _KERNEL */
 
 #endif /* !_ISA_ISAVAR_H_ */
index f9ebbdc..fbdfa1c 100644 (file)
@@ -90,36 +90,44 @@ static int dmapageport[8] = { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
 /*
  * Setup a DMA channel's bounce buffer.
  */
-void
-isa_dmainit(int chan, u_int bouncebufsize)
+int
+isa_dma_init(int chan, u_int bouncebufsize, int flags)
 {
        void *buf;
 
 #ifdef DIAGNOSTIC
        if (chan & ~VALID_DMA_MASK)
-               panic("isa_dmainit: channel out of range");
+               panic("isa_dma_init: channel out of range");
 
        if (dma_bouncebuf[chan] != NULL)
-               panic("isa_dmainit: impossible request"); 
+               panic("isa_dma_init: impossible request");
 #endif
 
-       dma_bouncebufsize[chan] = bouncebufsize;
-
        /* Try malloc() first.  It works better if it works. */
-       buf = kmalloc(bouncebufsize, M_DEVBUF, M_NOWAIT);
+       buf = kmalloc(bouncebufsize, M_DEVBUF, flags);
        if (buf != NULL) {
-               if (isa_dmarangecheck(buf, bouncebufsize, chan) == 0) {
-                       dma_bouncebuf[chan] = buf;
-                       return;
+               if (isa_dmarangecheck(buf, bouncebufsize, chan) != 0) {
+                       kfree(buf, M_DEVBUF);
+                       buf = NULL;
+                       if (bootverbose)
+                               kprintf("isa_dma_init: kmalloc rejected\n");
                }
-               kfree(buf, M_DEVBUF);
        }
-       buf = contigmalloc(bouncebufsize, M_DEVBUF, M_NOWAIT, 0ul, 0xfffffful,
-                          1ul, chan & 4 ? 0x20000ul : 0x10000ul);
-       if (buf == NULL)
-               kprintf("isa_dmainit(%d, %d) failed\n", chan, bouncebufsize);
-       else
-               dma_bouncebuf[chan] = buf;
+
+       if (buf == NULL) {
+               buf = contigmalloc(bouncebufsize, M_DEVBUF, flags, 0ul, 0xfffffful,
+                                  1ul, chan & 4 ? 0x20000ul : 0x10000ul);
+       }
+
+       if (buf == NULL) {
+               kprintf("isa_dma_init(%d, %d) failed\n", chan, bouncebufsize);
+               return ENOMEM;
+       }
+
+       dma_bouncebufsize[chan] = bouncebufsize;
+       dma_bouncebuf[chan] = buf;
+
+       return 0;
 }
 
 /*
index f93a54f..5bf5bea 100644 (file)
@@ -101,6 +101,8 @@ dev/raid/aac/aac_disk.c                     optional aac
 dev/raid/aac/aac_pci.c                 optional aac pci
 dev/raid/arcmsr/arcmsr.c               optional arcmsr pci
 
+dev/disk/fd/fd.c                       optional fd
+dev/disk/fd/fd_pccard.c                        optional fd pccard
 
 dev/pccard/pccbb/pccbb.c               optional cbb
 dev/pccard/pccbb/pccbb_isa.c           optional cbb isa
index 12a023e..42c0a6f 100644 (file)
@@ -998,17 +998,21 @@ options   ATA_STATIC_ID
 #device                nata1   at isa? port IO_WD2 irq 15
 
 #
-# Standard floppy disk controllers: `fdc' and `fd'
+# Standard floppy disk controllers: `fdc' and `fd' (see fdc(4))
 #
-#device                fdc0    at isa? port IO_FD1 irq 6 drq 2
+device         fdc0    at isa? port IO_FD1 irq 6 drq 2
 #
 # FDC_DEBUG enables floppy debugging.  Since the debug output is huge, you
 # gotta turn it actually on by setting the variable fd_debug with DDB,
 # however.
-#options       FDC_DEBUG
+options        FDC_DEBUG
 
-#device                fd0     at fdc0 drive 0
-#device                fd1     at fdc0 drive 1
+device         fd0     at fdc0 drive 0
+device         fd1     at fdc0 drive 1
+
+# LMC/SBE LMC1504 quad T1/E1 driver
+#
+device         musycc
 
 #
 # sio: serial ports (see sio(4))
index 69003dc..ac35be3 100644 (file)
@@ -795,8 +795,16 @@ fdc_attach(device_t dev)
        if ((fdc->flags & FDC_NODMA) == 0) {
                /* Acquire the DMA channel forever, The driver will do the rest */
                                /* XXX should integrate with rman */
-               isa_dma_acquire(fdc->dmachan);
-               isa_dmainit(fdc->dmachan, 128 << 3 /* XXX max secsize */);
+               error = isa_dma_acquire(fdc->dmachan);
+               if (!error) {
+                       isa_dma_init(fdc->dmachan, 128 << 3 /* XXX max secsize */,
+                                    M_WAITOK);
+                       if (error) {
+                               isa_dma_release(fdc->dmachan);
+                               device_printf(dev, "disabling dma\n");
+                               fdc->flags |= FDC_NODMA;
+                       }
+               }
        }
        fdc->state = DEVIDLE;
 
@@ -853,7 +861,9 @@ static driver_t fdc_driver = {
 };
 
 DRIVER_MODULE(fdc, isa, fdc_driver, fdc_devclass, NULL, NULL);
+#if 0
 DRIVER_MODULE(fdc, acpi, fdc_driver, fdc_devclass, NULL, NULL);
+#endif
 
 /******************************************************************/
 /*
@@ -879,7 +889,7 @@ fd_probe(device_t dev)
        fd->fdsu = fdsu;
        fd->fdu = device_get_unit(dev);
 
-#ifdef __i386__
+#ifdef __x86_64__
        /* look up what bios thinks we have */
        switch (fd->fdu) {
        case 0:
index f82271a..4ef1fc5 100644 (file)
@@ -28,7 +28,6 @@
  *
  *     from:   @(#)fd.c        7.4 (Berkeley) 5/25/91
  * $FreeBSD: src/sys/isa/fdc.h,v 1.20.2.3 2002/02/03 14:08:46 nyan Exp $
- * $DragonFly: src/sys/dev/disk/fd/fdc.h,v 1.7 2007/05/21 04:22:23 dillon Exp $
  *
  */
 
@@ -72,7 +71,7 @@ struct fdc_data
        bus_space_tag_t ctlt;
        bus_space_handle_t ctlh;
        void    *fdc_intr;
-       struct  device *fdc_dev;
+       device_t fdc_dev;
        struct  callout pseudointr_ch;
        void    (*fdctl_wr)(struct fdc_data *fdc, u_int8_t v);
 };
index e87408e..e74def6 100644 (file)
@@ -122,6 +122,19 @@ configure_first(void *dummy)
 static void
 configure(void *dummy)
 {
+#if NISA > 0
+       void *low_dma_reserve;
+
+       /*
+        * Try to reserve 512k of low dma memory for later isa attach.
+        * Document as a REALLY bad hack.
+        */
+       low_dma_reserve = contigmalloc(0x80000, M_TEMP, M_NOWAIT, 0ul,
+                                      0xfffffful, 1ul, 0x20000ul);
+       if (bootverbose)
+               kprintf("low dma reserve placed @ %p\n", low_dma_reserve);
+#endif
+
        /*
         * This will configure all devices, generally starting with the
         * nexus (i386/i386/nexus.c).  The nexus ISA code explicitly
@@ -132,6 +145,16 @@ configure(void *dummy)
        root_bus_configure();
 
 #if NISA > 0
+       /*
+        * Free up reserve if we got it.
+        */
+       if (low_dma_reserve != NULL) {
+               kprintf("Freeing low dma reserve @ %p\n", low_dma_reserve);
+               contigfree(low_dma_reserve, 0x80000, M_TEMP);
+       } else if (bootverbose) {
+               kprintf("low dma reserve was not allocated\n");
+       }
+
        /*
         * Explicitly probe and attach ISA last.  The isa bus saves
         * it's device node at attach time for us here.
index bd54912..9fbcc54 100644 (file)
@@ -416,7 +416,7 @@ vm_page_startup(void)
         * Construct the free queue(s) in ascending order (by physical
         * address) so that the first 16MB of physical memory is allocated
         * last rather than first.  On large-memory machines, this avoids
-        * the exhaustion of low physical memory before isa_dmainit has run.
+        * the exhaustion of low physical memory before isa_dma_init has run.
         */
        vmstats.v_page_count = 0;
        vmstats.v_free_count = 0;