summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Downs <downsj@cvs.openbsd.org>1996-06-20 07:51:38 +0000
committerJason Downs <downsj@cvs.openbsd.org>1996-06-20 07:51:38 +0000
commitf891a2d378fd94e732b4f03fdb5340c1a458eb89 (patch)
tree7439f1fe76b0367705ada4089b059b3b0a895cf3
parent95ed63a1d6fd46db236abe4f3d88fc550654e628 (diff)
fdformat support:
patches taken from jtk's dosemu for NetBSD 1.1 and updated for the current driver. Some of the code is based an older FreeBSD version of the driver.
-rw-r--r--sys/arch/i386/include/ioctl_fd.h129
-rw-r--r--sys/arch/i386/isa/fd.c176
-rw-r--r--sys/dev/isa/fd.c176
3 files changed, 411 insertions, 70 deletions
diff --git a/sys/arch/i386/include/ioctl_fd.h b/sys/arch/i386/include/ioctl_fd.h
new file mode 100644
index 00000000000..15683e94314
--- /dev/null
+++ b/sys/arch/i386/include/ioctl_fd.h
@@ -0,0 +1,129 @@
+/* $OpenBSD: ioctl_fd.h,v 1.1 1996/06/20 07:51:36 downsj Exp $ */
+/* $Id: ioctl_fd.h,v 1.1 1996/06/20 07:51:36 downsj Exp $ */
+
+/*
+ * Copyright (C) 1992-1994 by Joerg Wunsch, Dresden
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * From: Id: ioctl_fd.h,v 1.7 1994/10/30 19:17:39 joerg Exp
+ */
+
+#ifndef _I386_IOCTL_FD_H_
+#define _I386_IOCTL_FD_H_
+
+#define FD_FORMAT_VERSION 110 /* used to validate before formatting */
+#define FD_MAX_NSEC 36 /* highest known number of spt - allow for */
+ /* 2.88 MB drives */
+
+struct fd_formb {
+ int format_version; /* == FD_FORMAT_VERSION */
+ int cyl, head;
+ int transfer_rate; /* fdreg.h: FDC_???KBPS */
+
+ union {
+ struct fd_form_data {
+ /*
+ * DO NOT CHANGE THE LAYOUT OF THIS STRUCTS
+ * it is hardware-dependant since it exactly
+ * matches the byte sequence to write to FDC
+ * during its `format track' operation
+ */
+ u_char secshift; /* 0 -> 128, ...; usually 2 -> 512 */
+ u_char nsecs; /* must be <= FD_MAX_NSEC */
+ u_char gaplen; /* GAP 3 length; usually 84 */
+ u_char fillbyte; /* usually 0xf6 */
+ struct fd_idfield_data {
+ /*
+ * data to write into id fields;
+ * for obscure formats, they mustn't match
+ * the real values (but mostly do)
+ */
+ u_char cylno; /* 0 thru 79 (or 39) */
+ u_char headno; /* 0, or 1 */
+ u_char secno; /* starting at 1! */
+ u_char secsize; /* usually 2 */
+ } idfields[FD_MAX_NSEC]; /* 0 <= idx < nsecs used */
+ } structured;
+ u_char raw[1]; /* to have continuous indexed access */
+ } format_info;
+};
+
+/* make life easier */
+# define fd_formb_secshift format_info.structured.secshift
+# define fd_formb_nsecs format_info.structured.nsecs
+# define fd_formb_gaplen format_info.structured.gaplen
+# define fd_formb_fillbyte format_info.structured.fillbyte
+/* these data must be filled in for(i = 0; i < fd_formb_nsecs; i++) */
+# define fd_formb_cylno(i) format_info.structured.idfields[i].cylno
+# define fd_formb_headno(i) format_info.structured.idfields[i].headno
+# define fd_formb_secno(i) format_info.structured.idfields[i].secno
+# define fd_formb_secsize(i) format_info.structured.idfields[i].secsize
+
+/*
+ * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
+ * we tell them apart.
+ */
+struct fd_type {
+ int sectrac; /* sectors per track */
+ int heads; /* number of heads */
+ int seccyl; /* sectors per cylinder */
+ int secsize; /* size code for sectors */
+ int datalen; /* data len when secsize = 0 */
+ int steprate; /* step rate and head unload time */
+ int gap1; /* gap len between sectors */
+ int gap2; /* formatting gap */
+ int tracks; /* total num of tracks */
+ int size; /* size of disk in sectors */
+ int step; /* steps per cylinder */
+ int rate; /* transfer speed code */
+ char *name;
+};
+
+
+#define FD_FORM _IOW('F', 61, struct fd_formb) /* format a track */
+#define FD_GTYPE _IOR('F', 62, struct fd_type) /* get drive type */
+#define FD_STYPE _IOW('F', 63, struct fd_type) /* set drive type */
+
+#define FD_GOPTS _IOR('F', 64, int) /* drive options, see below */
+#define FD_SOPTS _IOW('F', 65, int)
+
+#define FDOPT_NORETRY 0x0001 /* no retries on failure (cleared on close) */
+
+/*
+ * The following definitions duplicate those in sys/i386/isa/fdreg.h
+ * They are here since their values are to be used in the above
+ * structure when formatting a floppy. For very obvious reasons, both
+ * definitions must match ;-)
+ */
+#ifndef FDC_500KBPS
+#define FDC_500KBPS 0x00 /* 500KBPS MFM drive transfer rate */
+#define FDC_300KBPS 0x01 /* 300KBPS MFM drive transfer rate */
+#define FDC_250KBPS 0x02 /* 250KBPS MFM drive transfer rate */
+#define FDC_125KBPS 0x03 /* 125KBPS FM drive transfer rate */
+ /* for some controllers 1MPBS instead */
+#endif /* FDC_500KBPS */
+
+
+#endif /* !_I386_IOCTL_FD_H__ */
diff --git a/sys/arch/i386/isa/fd.c b/sys/arch/i386/isa/fd.c
index a9a28c2f73a..065e19ccfe9 100644
--- a/sys/arch/i386/isa/fd.c
+++ b/sys/arch/i386/isa/fd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: fd.c,v 1.17 1996/06/09 19:40:28 deraadt Exp $ */
+/* $OpenBSD: fd.c,v 1.18 1996/06/20 07:51:37 downsj Exp $ */
/* $NetBSD: fd.c,v 1.90 1996/05/12 23:12:03 mycroft Exp $ */
/*-
@@ -9,6 +9,12 @@
* This code is derived from software contributed to Berkeley by
* Don Ahn.
*
+ * Portions Copyright (c) 1993, 1994 by
+ * jc@irbs.UUCP (John Capo)
+ * vak@zebub.msk.su (Serge Vakulenko)
+ * ache@astral.msk.su (Andrew A. Chernov)
+ * joerg_wunsch@uriah.sax.de (Joerg Wunsch)
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -50,6 +56,7 @@
#include <sys/dkstat.h>
#include <sys/disk.h>
#include <sys/buf.h>
+#include <sys/malloc.h>
#include <sys/uio.h>
#include <sys/mtio.h>
#include <sys/syslog.h>
@@ -59,6 +66,7 @@
#include <machine/bus.h>
#include <machine/conf.h>
#include <machine/intr.h>
+#include <machine/ioctl_fd.h>
#include <dev/isa/isavar.h>
#include <dev/isa/isadmavar.h>
@@ -70,6 +78,9 @@
#define FDUNIT(dev) (minor(dev) / 8)
#define FDTYPE(dev) (minor(dev) % 8)
+/* XXX misuse a flag to identify format operation */
+#define B_FORMAT B_XXX
+
#define b_cylin b_resid
enum fdc_state {
@@ -125,25 +136,7 @@ struct cfdriver fdc_cd = {
NULL, "fdc", DV_DULL
};
-/*
- * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
- * we tell them apart.
- */
-struct fd_type {
- int sectrac; /* sectors per track */
- int heads; /* number of heads */
- int seccyl; /* sectors per cylinder */
- int secsize; /* size code for sectors */
- int datalen; /* data len when secsize = 0 */
- int steprate; /* step rate and head unload time */
- int gap1; /* gap len between sectors */
- int gap2; /* formatting gap */
- int tracks; /* total num of tracks */
- int size; /* size of disk in sectors */
- int step; /* steps per cylinder */
- int rate; /* transfer speed code */
- char *name;
-};
+/* fd_type struct now in ioctl_fd.h */
/* The order of entries in the following table is important -- BEWARE! */
struct fd_type fd_types[] = {
@@ -166,6 +159,7 @@ struct fd_softc {
daddr_t sc_blkno; /* starting block number */
int sc_bcount; /* byte count left */
+ int sc_opts; /* user-set options */
int sc_skip; /* bytes already transferred */
int sc_nblks; /* number of blocks currently tranferring */
int sc_nbytes; /* number of bytes currently tranferring */
@@ -216,6 +210,7 @@ void fdcpseudointr __P((void *arg));
int fdcintr __P((void *));
void fdcretry __P((struct fdc_softc *fdc));
void fdfinish __P((struct fd_softc *fd, struct buf *bp));
+int fdformat __P((dev_t, struct fd_formb *, struct proc *));
__inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
int
@@ -519,7 +514,8 @@ fdstrategy(bp)
if (unit >= fd_cd.cd_ndevs ||
(fd = fd_cd.cd_devs[unit]) == 0 ||
bp->b_blkno < 0 ||
- (bp->b_bcount % FDC_BSIZE) != 0) {
+ ((bp->b_bcount % FDC_BSIZE) != 0 &&
+ (bp->b_flags & B_FORMAT) == 0)) {
bp->b_error = EINVAL;
goto bad;
}
@@ -781,6 +777,7 @@ fdclose(dev, flags, mode, p)
struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
fd->sc_flags &= ~FD_OPEN;
+ fd->sc_opts &= ~FDOPT_NORETRY;
return 0;
}
@@ -849,6 +846,9 @@ fdctimeout(arg)
int s;
s = splbio();
+#ifdef DEBUG
+ log(LOG_ERR,"fdctimeout: state %d\n", fdc->sc_state);
+#endif
fdcstatus(&fd->sc_dev, 0, "timeout");
if (fd->sc_q.b_actf)
@@ -885,6 +885,7 @@ fdcintr(arg)
bus_io_handle_t ioh = fdc->sc_ioh;
int read, head, sec, i, nblks;
struct fd_type *type;
+ struct fd_formb *finfo = NULL;
loop:
/* Is there a drive for the controller to do a transfer with? */
@@ -903,6 +904,9 @@ loop:
goto loop;
}
+ if (bp->b_flags & B_FORMAT)
+ finfo = (struct fd_formb *)bp->b_data;
+
switch (fdc->sc_state) {
case DEVIDLE:
fdc->sc_errors = 0;
@@ -957,12 +961,15 @@ loop:
case DOIO:
doio:
type = fd->sc_type;
+ if (finfo)
+ fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
+ (char *)finfo;
sec = fd->sc_blkno % type->seccyl;
nblks = type->seccyl - sec;
nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
fd->sc_nblks = nblks;
- fd->sc_nbytes = nblks * FDC_BSIZE;
+ fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
head = sec / type->sectrac;
sec -= head * type->sectrac;
#ifdef DIAGNOSTIC
@@ -989,18 +996,32 @@ loop:
read ? "read" : "write", fd->sc_drive, fd->sc_cylin, head,
sec, nblks);
#endif
- if (read)
- out_fdc(bc, ioh, NE7CMD_READ); /* READ */
- else
- out_fdc(bc, ioh, NE7CMD_WRITE); /* WRITE */
- out_fdc(bc, ioh, (head << 2) | fd->sc_drive);
- out_fdc(bc, ioh, fd->sc_cylin); /* track */
- out_fdc(bc, ioh, head);
- out_fdc(bc, ioh, sec + 1); /* sector +1 */
- out_fdc(bc, ioh, type->secsize); /* sector size */
- out_fdc(bc, ioh, type->sectrac); /* sectors/track */
- out_fdc(bc, ioh, type->gap1); /* gap1 size */
- out_fdc(bc, ioh, type->datalen); /* data length */
+ if (finfo) {
+ /* formatting */
+ if (out_fdc(bc, ioh, NE7CMD_FORMAT) < 0) {
+ fdc->sc_errors = 4;
+ fdcretry(fdc);
+ goto loop;
+ }
+ out_fdc(bc, ioh, (head << 2) | fd->sc_drive);
+ out_fdc(bc, ioh, finfo->fd_formb_secshift);
+ out_fdc(bc, ioh, finfo->fd_formb_nsecs);
+ out_fdc(bc, ioh, finfo->fd_formb_gaplen);
+ out_fdc(bc, ioh, finfo->fd_formb_fillbyte);
+ } else {
+ if (read)
+ out_fdc(bc, ioh, NE7CMD_READ); /* READ */
+ else
+ out_fdc(bc, ioh, NE7CMD_WRITE); /* WRITE */
+ out_fdc(bc, ioh, (head << 2) | fd->sc_drive);
+ out_fdc(bc, ioh, fd->sc_cylin); /* track */
+ out_fdc(bc, ioh, head);
+ out_fdc(bc, ioh, sec + 1); /* sector +1 */
+ out_fdc(bc, ioh, type->secsize); /* sector size */
+ out_fdc(bc, ioh, type->sectrac); /* sectors/track */
+ out_fdc(bc, ioh, type->gap1); /* gap1 size */
+ out_fdc(bc, ioh, type->datalen); /* data length */
+ }
fdc->sc_state = IOCOMPLETE;
disk_busy(&fd->sc_dk);
@@ -1080,7 +1101,7 @@ loop:
fd->sc_blkno += fd->sc_nblks;
fd->sc_skip += fd->sc_nbytes;
fd->sc_bcount -= fd->sc_nbytes;
- if (fd->sc_bcount > 0) {
+ if (!finfo && fd->sc_bcount > 0) {
bp->b_cylin = fd->sc_blkno / fd->sc_type->seccyl;
goto doseek;
}
@@ -1157,6 +1178,8 @@ fdcretry(fdc)
fd = fdc->sc_drives.tqh_first;
bp = fd->sc_q.b_actf;
+ if (fd->sc_opts & FDOPT_NORETRY)
+ goto fail;
switch (fdc->sc_errors) {
case 0:
/* try again */
@@ -1174,6 +1197,7 @@ fdcretry(fdc)
break;
default:
+ fail:
diskerr(bp, "fd", "hard error", LOG_PRINTF,
fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n",
@@ -1257,6 +1281,28 @@ fdioctl(dev, cmd, addr, flag, p)
error = writedisklabel(dev, fdstrategy, &buffer, NULL);
return error;
+ case FD_FORM:
+ if((flag & FWRITE) == 0)
+ return EBADF; /* must be opened for writing */
+ else if(((struct fd_formb *)addr)->format_version !=
+ FD_FORMAT_VERSION)
+ return EINVAL; /* wrong version of formatting prog */
+ else
+ return fdformat(dev, (struct fd_formb *)addr, p);
+ break;
+
+ case FD_GTYPE: /* get drive type */
+ *(struct fd_type *)addr = *fd->sc_type;
+ return 0;
+
+ case FD_GOPTS: /* get drive options */
+ *(int *)addr = fd->sc_opts;
+ return 0;
+
+ case FD_SOPTS: /* set drive options */
+ fd->sc_opts = *(int *)addr;
+ return 0;
+
default:
return ENOTTY;
}
@@ -1265,3 +1311,63 @@ fdioctl(dev, cmd, addr, flag, p)
panic("fdioctl: impossible");
#endif
}
+
+int
+fdformat(dev, finfo, p)
+ dev_t dev;
+ struct fd_formb *finfo;
+ struct proc *p;
+{
+ int rv = 0, s;
+ struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
+ struct fd_type *type = fd->sc_type;
+ struct buf *bp;
+
+ /* set up a buffer header for fdstrategy() */
+ bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
+ if(bp == 0)
+ return ENOBUFS;
+ bzero((void *)bp, sizeof(struct buf));
+ bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
+ bp->b_proc = p;
+ bp->b_dev = dev;
+
+ /*
+ * calculate a fake blkno, so fdstrategy() would initiate a
+ * seek to the requested cylinder
+ */
+ bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
+ + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
+
+ bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
+ bp->b_data = (caddr_t)finfo;
+
+#ifdef DEBUG
+ printf("fdformat: blkno %x count %x\n", bp->b_blkno, bp->b_bcount);
+#endif
+
+ /* now do the format */
+ fdstrategy(bp);
+
+ /* ...and wait for it to complete */
+ s = splbio();
+ while(!(bp->b_flags & B_DONE))
+ {
+ rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 0);
+ if(rv == EWOULDBLOCK)
+ /*break*/;
+ }
+ splx(s);
+
+ if(rv == EWOULDBLOCK) {
+ /* timed out */
+ rv = EIO;
+ /* XXX what to do to the buf? it will eventually fall
+ out as finished, but ... ?*/
+ /*biodone(bp);*/
+ }
+ if(bp->b_flags & B_ERROR)
+ rv = bp->b_error;
+ free(bp, M_TEMP);
+ return rv;
+}
diff --git a/sys/dev/isa/fd.c b/sys/dev/isa/fd.c
index a9a28c2f73a..065e19ccfe9 100644
--- a/sys/dev/isa/fd.c
+++ b/sys/dev/isa/fd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: fd.c,v 1.17 1996/06/09 19:40:28 deraadt Exp $ */
+/* $OpenBSD: fd.c,v 1.18 1996/06/20 07:51:37 downsj Exp $ */
/* $NetBSD: fd.c,v 1.90 1996/05/12 23:12:03 mycroft Exp $ */
/*-
@@ -9,6 +9,12 @@
* This code is derived from software contributed to Berkeley by
* Don Ahn.
*
+ * Portions Copyright (c) 1993, 1994 by
+ * jc@irbs.UUCP (John Capo)
+ * vak@zebub.msk.su (Serge Vakulenko)
+ * ache@astral.msk.su (Andrew A. Chernov)
+ * joerg_wunsch@uriah.sax.de (Joerg Wunsch)
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -50,6 +56,7 @@
#include <sys/dkstat.h>
#include <sys/disk.h>
#include <sys/buf.h>
+#include <sys/malloc.h>
#include <sys/uio.h>
#include <sys/mtio.h>
#include <sys/syslog.h>
@@ -59,6 +66,7 @@
#include <machine/bus.h>
#include <machine/conf.h>
#include <machine/intr.h>
+#include <machine/ioctl_fd.h>
#include <dev/isa/isavar.h>
#include <dev/isa/isadmavar.h>
@@ -70,6 +78,9 @@
#define FDUNIT(dev) (minor(dev) / 8)
#define FDTYPE(dev) (minor(dev) % 8)
+/* XXX misuse a flag to identify format operation */
+#define B_FORMAT B_XXX
+
#define b_cylin b_resid
enum fdc_state {
@@ -125,25 +136,7 @@ struct cfdriver fdc_cd = {
NULL, "fdc", DV_DULL
};
-/*
- * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
- * we tell them apart.
- */
-struct fd_type {
- int sectrac; /* sectors per track */
- int heads; /* number of heads */
- int seccyl; /* sectors per cylinder */
- int secsize; /* size code for sectors */
- int datalen; /* data len when secsize = 0 */
- int steprate; /* step rate and head unload time */
- int gap1; /* gap len between sectors */
- int gap2; /* formatting gap */
- int tracks; /* total num of tracks */
- int size; /* size of disk in sectors */
- int step; /* steps per cylinder */
- int rate; /* transfer speed code */
- char *name;
-};
+/* fd_type struct now in ioctl_fd.h */
/* The order of entries in the following table is important -- BEWARE! */
struct fd_type fd_types[] = {
@@ -166,6 +159,7 @@ struct fd_softc {
daddr_t sc_blkno; /* starting block number */
int sc_bcount; /* byte count left */
+ int sc_opts; /* user-set options */
int sc_skip; /* bytes already transferred */
int sc_nblks; /* number of blocks currently tranferring */
int sc_nbytes; /* number of bytes currently tranferring */
@@ -216,6 +210,7 @@ void fdcpseudointr __P((void *arg));
int fdcintr __P((void *));
void fdcretry __P((struct fdc_softc *fdc));
void fdfinish __P((struct fd_softc *fd, struct buf *bp));
+int fdformat __P((dev_t, struct fd_formb *, struct proc *));
__inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
int
@@ -519,7 +514,8 @@ fdstrategy(bp)
if (unit >= fd_cd.cd_ndevs ||
(fd = fd_cd.cd_devs[unit]) == 0 ||
bp->b_blkno < 0 ||
- (bp->b_bcount % FDC_BSIZE) != 0) {
+ ((bp->b_bcount % FDC_BSIZE) != 0 &&
+ (bp->b_flags & B_FORMAT) == 0)) {
bp->b_error = EINVAL;
goto bad;
}
@@ -781,6 +777,7 @@ fdclose(dev, flags, mode, p)
struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
fd->sc_flags &= ~FD_OPEN;
+ fd->sc_opts &= ~FDOPT_NORETRY;
return 0;
}
@@ -849,6 +846,9 @@ fdctimeout(arg)
int s;
s = splbio();
+#ifdef DEBUG
+ log(LOG_ERR,"fdctimeout: state %d\n", fdc->sc_state);
+#endif
fdcstatus(&fd->sc_dev, 0, "timeout");
if (fd->sc_q.b_actf)
@@ -885,6 +885,7 @@ fdcintr(arg)
bus_io_handle_t ioh = fdc->sc_ioh;
int read, head, sec, i, nblks;
struct fd_type *type;
+ struct fd_formb *finfo = NULL;
loop:
/* Is there a drive for the controller to do a transfer with? */
@@ -903,6 +904,9 @@ loop:
goto loop;
}
+ if (bp->b_flags & B_FORMAT)
+ finfo = (struct fd_formb *)bp->b_data;
+
switch (fdc->sc_state) {
case DEVIDLE:
fdc->sc_errors = 0;
@@ -957,12 +961,15 @@ loop:
case DOIO:
doio:
type = fd->sc_type;
+ if (finfo)
+ fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
+ (char *)finfo;
sec = fd->sc_blkno % type->seccyl;
nblks = type->seccyl - sec;
nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
fd->sc_nblks = nblks;
- fd->sc_nbytes = nblks * FDC_BSIZE;
+ fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
head = sec / type->sectrac;
sec -= head * type->sectrac;
#ifdef DIAGNOSTIC
@@ -989,18 +996,32 @@ loop:
read ? "read" : "write", fd->sc_drive, fd->sc_cylin, head,
sec, nblks);
#endif
- if (read)
- out_fdc(bc, ioh, NE7CMD_READ); /* READ */
- else
- out_fdc(bc, ioh, NE7CMD_WRITE); /* WRITE */
- out_fdc(bc, ioh, (head << 2) | fd->sc_drive);
- out_fdc(bc, ioh, fd->sc_cylin); /* track */
- out_fdc(bc, ioh, head);
- out_fdc(bc, ioh, sec + 1); /* sector +1 */
- out_fdc(bc, ioh, type->secsize); /* sector size */
- out_fdc(bc, ioh, type->sectrac); /* sectors/track */
- out_fdc(bc, ioh, type->gap1); /* gap1 size */
- out_fdc(bc, ioh, type->datalen); /* data length */
+ if (finfo) {
+ /* formatting */
+ if (out_fdc(bc, ioh, NE7CMD_FORMAT) < 0) {
+ fdc->sc_errors = 4;
+ fdcretry(fdc);
+ goto loop;
+ }
+ out_fdc(bc, ioh, (head << 2) | fd->sc_drive);
+ out_fdc(bc, ioh, finfo->fd_formb_secshift);
+ out_fdc(bc, ioh, finfo->fd_formb_nsecs);
+ out_fdc(bc, ioh, finfo->fd_formb_gaplen);
+ out_fdc(bc, ioh, finfo->fd_formb_fillbyte);
+ } else {
+ if (read)
+ out_fdc(bc, ioh, NE7CMD_READ); /* READ */
+ else
+ out_fdc(bc, ioh, NE7CMD_WRITE); /* WRITE */
+ out_fdc(bc, ioh, (head << 2) | fd->sc_drive);
+ out_fdc(bc, ioh, fd->sc_cylin); /* track */
+ out_fdc(bc, ioh, head);
+ out_fdc(bc, ioh, sec + 1); /* sector +1 */
+ out_fdc(bc, ioh, type->secsize); /* sector size */
+ out_fdc(bc, ioh, type->sectrac); /* sectors/track */
+ out_fdc(bc, ioh, type->gap1); /* gap1 size */
+ out_fdc(bc, ioh, type->datalen); /* data length */
+ }
fdc->sc_state = IOCOMPLETE;
disk_busy(&fd->sc_dk);
@@ -1080,7 +1101,7 @@ loop:
fd->sc_blkno += fd->sc_nblks;
fd->sc_skip += fd->sc_nbytes;
fd->sc_bcount -= fd->sc_nbytes;
- if (fd->sc_bcount > 0) {
+ if (!finfo && fd->sc_bcount > 0) {
bp->b_cylin = fd->sc_blkno / fd->sc_type->seccyl;
goto doseek;
}
@@ -1157,6 +1178,8 @@ fdcretry(fdc)
fd = fdc->sc_drives.tqh_first;
bp = fd->sc_q.b_actf;
+ if (fd->sc_opts & FDOPT_NORETRY)
+ goto fail;
switch (fdc->sc_errors) {
case 0:
/* try again */
@@ -1174,6 +1197,7 @@ fdcretry(fdc)
break;
default:
+ fail:
diskerr(bp, "fd", "hard error", LOG_PRINTF,
fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n",
@@ -1257,6 +1281,28 @@ fdioctl(dev, cmd, addr, flag, p)
error = writedisklabel(dev, fdstrategy, &buffer, NULL);
return error;
+ case FD_FORM:
+ if((flag & FWRITE) == 0)
+ return EBADF; /* must be opened for writing */
+ else if(((struct fd_formb *)addr)->format_version !=
+ FD_FORMAT_VERSION)
+ return EINVAL; /* wrong version of formatting prog */
+ else
+ return fdformat(dev, (struct fd_formb *)addr, p);
+ break;
+
+ case FD_GTYPE: /* get drive type */
+ *(struct fd_type *)addr = *fd->sc_type;
+ return 0;
+
+ case FD_GOPTS: /* get drive options */
+ *(int *)addr = fd->sc_opts;
+ return 0;
+
+ case FD_SOPTS: /* set drive options */
+ fd->sc_opts = *(int *)addr;
+ return 0;
+
default:
return ENOTTY;
}
@@ -1265,3 +1311,63 @@ fdioctl(dev, cmd, addr, flag, p)
panic("fdioctl: impossible");
#endif
}
+
+int
+fdformat(dev, finfo, p)
+ dev_t dev;
+ struct fd_formb *finfo;
+ struct proc *p;
+{
+ int rv = 0, s;
+ struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
+ struct fd_type *type = fd->sc_type;
+ struct buf *bp;
+
+ /* set up a buffer header for fdstrategy() */
+ bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
+ if(bp == 0)
+ return ENOBUFS;
+ bzero((void *)bp, sizeof(struct buf));
+ bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
+ bp->b_proc = p;
+ bp->b_dev = dev;
+
+ /*
+ * calculate a fake blkno, so fdstrategy() would initiate a
+ * seek to the requested cylinder
+ */
+ bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
+ + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
+
+ bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
+ bp->b_data = (caddr_t)finfo;
+
+#ifdef DEBUG
+ printf("fdformat: blkno %x count %x\n", bp->b_blkno, bp->b_bcount);
+#endif
+
+ /* now do the format */
+ fdstrategy(bp);
+
+ /* ...and wait for it to complete */
+ s = splbio();
+ while(!(bp->b_flags & B_DONE))
+ {
+ rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 0);
+ if(rv == EWOULDBLOCK)
+ /*break*/;
+ }
+ splx(s);
+
+ if(rv == EWOULDBLOCK) {
+ /* timed out */
+ rv = EIO;
+ /* XXX what to do to the buf? it will eventually fall
+ out as finished, but ... ?*/
+ /*biodone(bp);*/
+ }
+ if(bp->b_flags & B_ERROR)
+ rv = bp->b_error;
+ free(bp, M_TEMP);
+ return rv;
+}