Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/x68k/dev Add floppy format support. Mostly taken f...



details:   https://anonhg.NetBSD.org/src/rev/e790c9d36233
branches:  trunk
changeset: 782080:e790c9d36233
user:      tsutsui <tsutsui%NetBSD.org@localhost>
date:      Sun Oct 14 18:38:32 2012 +0000

description:
Add floppy format support.  Mostly taken from sys/dev/isa/fd.c.

Tested both fdNa (1232KB, 1024bytes/sector, 8sectors/track) and
fdNc (1200KB, 512bytes/sector, 15sectors/track) format on X68030
using fdformat(1).

Finally we can prepare NetBSD/x68k install floppies without Human68k
(except actual initial bootstrap).

diffstat:

 sys/arch/x68k/dev/fd.c    |  283 +++++++++++++++++++++++++++++++++++++++++----
 sys/arch/x68k/dev/fdreg.h |   51 ++++++++-
 2 files changed, 303 insertions(+), 31 deletions(-)

diffs (truncated from 493 to 300 lines):

diff -r 43330750df32 -r e790c9d36233 sys/arch/x68k/dev/fd.c
--- a/sys/arch/x68k/dev/fd.c    Sun Oct 14 18:37:55 2012 +0000
+++ b/sys/arch/x68k/dev/fd.c    Sun Oct 14 18:38:32 2012 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: fd.c,v 1.103 2012/10/14 17:25:59 tsutsui Exp $ */
+/*     $NetBSD: fd.c,v 1.104 2012/10/14 18:38:32 tsutsui Exp $ */
 
 /*-
  * Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -64,7 +64,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.103 2012/10/14 17:25:59 tsutsui Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.104 2012/10/14 18:38:32 tsutsui Exp $");
 
 #include "opt_ddb.h"
 #include "opt_m68k_arch.h"
@@ -87,6 +87,7 @@
 #include <sys/uio.h>
 #include <sys/syslog.h>
 #include <sys/queue.h>
+#include <sys/proc.h>
 #include <sys/fdio.h>
 #include <sys/rnd.h>
 
@@ -112,6 +113,9 @@
 #define FDUNIT(dev)    (minor(dev) / 8)
 #define FDTYPE(dev)    (minor(dev) % 8)
 
+/* (mis)use device use flag to identify format operation */
+#define B_FORMAT B_DEVPRIVATE
+
 enum fdc_state {
        DEVIDLE = 0,
        MOTORWAIT,
@@ -184,19 +188,29 @@
        int     size;           /* size of disk in sectors */
        int     step;           /* steps per cylinder */
        int     rate;           /* transfer speed code */
+       uint8_t fillbyte;       /* format fill byte */
+       uint8_t interleave;     /* interleave factor (formatting) */
        const char *name;
 };
 
 /* The order of entries in the following table is important -- BEWARE! */
 struct fd_type fd_types[] = {
-        {  8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, "1.2MB/[1024bytes/sector]"    }, /* 1.2 MB japanese format */
-        { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB"    }, /* 1.44MB diskette */
-        { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB"    }, /* 1.2 MB AT-diskettes */
-        {  9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */
-        {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
-        {  9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB"    }, /* 3.5" 720kB diskette */
-        {  9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x"  }, /* 720kB in 1.2MB drive */
-        {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x"  }, /* 360kB in 720kB drive */
+       {  8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, 0xf6, 1,
+           "1.2MB/[1024bytes/sector]"    }, /* 1.2 MB japanese format */
+       { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS, 0xf6, 1,
+           "1.44MB"    }, /* 1.44MB diskette */
+       { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, 0xf6, 1,
+           "1.2MB"    }, /* 1.2 MB AT-diskettes */
+       {  9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, 0xf6, 1,
+           "360KB/AT" }, /* 360kB in 1.2MB drive */
+       {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, 0xf6, 1,
+           "360KB/PC" }, /* 360kB PC diskettes */
+       {  9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, 0xf6, 1,
+           "720KB"    }, /* 3.5" 720kB diskette */
+       {  9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, 0xf6, 1,
+           "720KB/x"  }, /* 720kB in 1.2MB drive */
+       {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, 0xf6, 1,
+           "360KB/x"  }, /* 360kB in 720kB drive */
 };
 
 /* software state, per disk (with up to 4 disks per ctlr) */
@@ -283,6 +297,7 @@
 void fdcretry(struct fdc_softc *);
 void fdfinish(struct fd_softc *, struct buf *);
 inline struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t);
+int fdformat(dev_t, struct ne7_fd_formb *, struct lwp *);
 static int fdcpoll(struct fdc_softc *);
 static int fdgetdisklabel(struct fd_softc *, dev_t);
 static void fd_do_eject(struct fdc_softc *, int);
@@ -659,7 +674,8 @@
        }
 
        if (bp->b_blkno < 0 ||
-           (bp->b_bcount % FDC_BSIZE) != 0) {
+           ((bp->b_bcount % FDC_BSIZE) != 0 &&
+            (bp->b_flags & B_FORMAT) == 0)) {
                DPRINTF(("fdstrategy: unit=%d, blkno=%" PRId64 ", "
                    "bcount=%d\n", unit,
                    bp->b_blkno, bp->b_bcount));
@@ -943,6 +959,9 @@
                break;
        }
 
+       /* clear flags */
+       fd->sc_opts &= ~(FDOPT_NORETRY | FDOPT_SILENT);
+
        if ((fd->sc_flags & FD_OPEN) == 0) {
                bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
                    (1 << unit));
@@ -1059,6 +1078,7 @@
        int read, head, sec, pos, i, sectrac, nblks;
        int tmp;
        struct fd_type *type;
+       struct ne7_fd_formb *finfo = NULL;
 
  loop:
        fd = TAILQ_FIRST(&fdc->sc_drives);
@@ -1088,6 +1108,9 @@
                goto loop;
        }
 
+       if (bp->b_flags & B_FORMAT)
+               finfo = (struct ne7_fd_formb *)bp->b_data;
+
        switch (fdc->sc_state) {
        case DEVIDLE:
                DPRINTF(("fdcintr: in DEVIDLE\n"));
@@ -1154,10 +1177,13 @@
        doio:
                DPRINTF(("fdcintr: DOIO: "));
                type = fd->sc_type;
+               if (finfo != NULL)
+                       fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
+                           (char *)finfo;
                sectrac = type->sectrac;
                pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
                sec = pos / (1 << (type->secsize - 2));
-               if (type->secsize == 2) {
+               if (finfo != NULL || type->secsize == 2) {
                        fd->sc_part = SEC_P11;
                        nblks = (sectrac - sec) << (type->secsize - 2);
                        nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
@@ -1189,7 +1215,8 @@
                nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
                DPRINTF((" %d\n", nblks));
                fd->sc_nblks = nblks;
-               fd->sc_nbytes = nblks * FDC_BSIZE;
+               fd->sc_nbytes =
+                   (finfo != NULL) ? bp->b_bcount : nblks * FDC_BSIZE;
                head = (fd->sc_blkno
                    % (type->seccyl * (1 << (type->secsize - 2))))
                    / (type->sectrac * (1 << (type->secsize - 2)));
@@ -1220,23 +1247,37 @@
                DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
                    type->secsize));
 
-               if (fd->sc_part != SEC_P11)
+               if (finfo == NULL && fd->sc_part != SEC_P11)
                        goto docopy;
 
                fdc_dmastart(fdc, read, (char *)bp->b_data + fd->sc_skip,
                    fd->sc_nbytes);
-               if (read)
-                       out_fdc(iot, ioh, NE7CMD_READ); /* READ */
-               else
-                       out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
-               out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
-               out_fdc(iot, ioh, bp->b_cylinder);      /* cylinder */
-               out_fdc(iot, ioh, head);
-               out_fdc(iot, ioh, sec + 1);             /* sector +1 */
-               out_fdc(iot, ioh, type->secsize);       /* sector size */
-               out_fdc(iot, ioh, type->sectrac);       /* sectors/track */
-               out_fdc(iot, ioh, type->gap1);          /* gap1 size */
-               out_fdc(iot, ioh, type->datalen);       /* data length */
+               if (finfo != NULL) {
+                       /* formatting */
+                       if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) {
+                               fdc->sc_errors = 4;
+                               fdcretry(fdc);
+                               goto loop;
+                       }
+                       out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
+                       out_fdc(iot, ioh, finfo->fd_formb_secshift);
+                       out_fdc(iot, ioh, finfo->fd_formb_nsecs);
+                       out_fdc(iot, ioh, finfo->fd_formb_gaplen);
+                       out_fdc(iot, ioh, finfo->fd_formb_fillbyte);
+               } else {
+                       if (read)
+                               out_fdc(iot, ioh, NE7CMD_READ); /* READ */
+                       else
+                               out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
+                       out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
+                       out_fdc(iot, ioh, bp->b_cylinder);      /* cylinder */
+                       out_fdc(iot, ioh, head);
+                       out_fdc(iot, ioh, sec + 1);             /* sector +1 */
+                       out_fdc(iot, ioh, type->secsize); /* sector size */
+                       out_fdc(iot, ioh, type->sectrac); /* sectors/track */
+                       out_fdc(iot, ioh, type->gap1);          /* gap1 size */
+                       out_fdc(iot, ioh, type->datalen); /* data length */
+               }
                fdc->sc_state = IOCOMPLETE;
 
                disk_busy(&fd->sc_dk);
@@ -1385,7 +1426,7 @@
                fd->sc_skip += fd->sc_nbytes;
                fd->sc_bcount -= fd->sc_nbytes;
                DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
-               if (fd->sc_bcount > 0) {
+               if (finfo == NULL && fd->sc_bcount > 0) {
                        bp->b_cylinder = fd->sc_blkno
                            / (fd->sc_type->seccyl
                            * (1 << (fd->sc_type->secsize - 2)));
@@ -1505,6 +1546,9 @@
        fd = TAILQ_FIRST(&fdc->sc_drives);
        bp = bufq_peek(fd->sc_q);
 
+       if (fd->sc_opts & FDOPT_NORETRY)
+               goto fail;
+
        switch (fdc->sc_errors) {
        case 0:
                /* try again */
@@ -1524,9 +1568,12 @@
                break;
 
        default:
-               diskerr(bp, "fd", "hard error", LOG_PRINTF,
-                   fd->sc_skip, (struct disklabel *)NULL);
-               fdcpstatus(7, fdc);
+       fail:
+               if ((fd->sc_opts & FDOPT_SILENT) == 0) {
+                       diskerr(bp, "fd", "hard error", LOG_PRINTF,
+                           fd->sc_skip, (struct disklabel *)NULL);
+                       fdcpstatus(7, fdc);
+               }
 
                bp->b_error = EIO;
                fdfinish(fd, bp);
@@ -1539,9 +1586,15 @@
 {
        struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
        struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
+       struct fdformat_parms *form_parms;
+       struct fdformat_cmd *form_cmd;
+       struct ne7_fd_formb *fd_formb;
        int part = DISKPART(dev);
        struct disklabel buffer;
        int error;
+       unsigned int scratch;
+       int il[FD_MAX_NSEC + 1];
+       int i, j;
 
        DPRINTF(("fdioctl:"));
        switch (cmd) {
@@ -1591,6 +1644,134 @@
                error = writedisklabel(dev, fdstrategy, &buffer, NULL);
                return error;
 
+       case FDIOCGETFORMAT:
+               DPRINTF(("FDIOCGETFORMAT\n"));
+               form_parms = (struct fdformat_parms *)addr;
+               form_parms->fdformat_version = FDFORMAT_VERSION;
+               form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
+               form_parms->ncyl = fd->sc_type->cyls;
+               form_parms->nspt = fd->sc_type->sectrac;
+               form_parms->ntrk = fd->sc_type->heads;
+               form_parms->stepspercyl = fd->sc_type->step;
+               form_parms->gaplen = fd->sc_type->gap2;
+               form_parms->fillbyte = fd->sc_type->fillbyte;
+               form_parms->interleave = fd->sc_type->interleave;
+               switch (fd->sc_type->rate) {
+               case FDC_500KBPS:
+                       form_parms->xfer_rate = 500 * 1024;
+                       break;
+               case FDC_300KBPS:
+                       form_parms->xfer_rate = 300 * 1024;
+                       break;
+               case FDC_250KBPS:
+                       form_parms->xfer_rate = 250 * 1024;
+                       break;
+               default:
+                       return EINVAL;
+               }
+               return 0;
+
+       case FDIOCSETFORMAT:
+               DPRINTF(("FDIOCSETFORMAT\n"));
+               if((flag & FWRITE) == 0)
+                       return EBADF;   /* must be opened for writing */
+               form_parms = (struct fdformat_parms *)addr;
+               if (form_parms->fdformat_version != FDFORMAT_VERSION)
+                       return EINVAL;  /* wrong version of formatting prog */
+
+               scratch = form_parms->nbps >> 7;
+               if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
+                   scratch & ~(1 << (ffs(scratch) - 1)))
+                       /* not a power-of-two multiple of 128 */
+                       return EINVAL;
+
+               switch (form_parms->xfer_rate) {
+               case 500 * 1024:
+                       fd->sc_type->rate = FDC_500KBPS;
+                       break;
+               case 300 * 1024:
+                       fd->sc_type->rate = FDC_300KBPS;
+                       break;
+               case 250 * 1024:



Home | Main Index | Thread Index | Old Index