Subject: Re: WANTED: Floppy formatter
To: None <peter@wonderland.org>
From: Mike Long <mike.long@analog.com>
List: port-i386
Date: 06/19/1995 11:10:37
>From: Peter Galbavy <peter@wonderland.org>
>Date: Sat, 17 Jun 1995 13:59:42 +0100 (BST)
>
>I am trying to move the office systems here to NetBSD, and the only
>thing that I *really* need is to be able to format floppies. What
>a bummer. Oh, and verify of course.
>
>Has someone got an fdformat and diffs to -current they couls point
>me at, please ?
Here is something I saved a couple of months ago (I'm such a pack
rat). I have not tried it out for myself. I think the floppy driver
has changed a bit since April, so it may take some work to get it to
function.
----------------------------------------------------------------------
Newsgroups: comp.unix.bsd.netbsd.misc
From: jtk@atria.com (John Kohl)
Subject: Re: format_fd0
In-Reply-To: kstailey@leidecker.gsfc.nasa.gov's message of 05 Apr 1995 20:34:36 GMT
Nntp-Posting-Host: banana.atria.com
Organization: Atria Software, Inc.
Date: 07 Apr 1995 08:47:43 -0400
>>>>> "Kenneth" == Kenneth Stailey <kstailey@leidecker.gsfc.nasa.gov> writes:
In article <KSTAILEY.95Apr5163436@leidecker.gsfc.nasa.gov> kstailey@leidecker.gsfc.nasa.gov (Kenneth Stailey) writes:
Kenneth> Yes, I heard that someone had a NetBSD/i386 that could do this. Does
Kenneth> anyone know about it?
Here are diffs from my system at home. Code sucked in from FreeBSD
floppy driver about 4 months ago.
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by John Kohl <jtk@earth> on Fri Apr 7 08:29:14 1995
#
# This archive contains:
# fdformat
#
# Error checking via sum(1) will be performed.
LANG=""; export LANG
PATH=/bin:/usr/bin:$PATH; export PATH
if sum -r </dev/null >/dev/null 2>&1
then
sumopt='-r'
else
sumopt=''
fi
echo mkdir - fdformat
mkdir fdformat
echo x - fdformat/Makefile
sed 's/^@//' >fdformat/Makefile <<'@EOF'
#
PROG = fdformat
# the -I's seem to be confusing, but necessery this way
# (so the right <unistd.h> will be found in /usr/include, and the
# "../i386/isa/ic/nec765.h" included from fdreg.h is accessible, too)
CFLAGS+= -Wall
@.include <bsd.prog.mk>
@EOF
set `sum $sumopt <fdformat/Makefile`; if test $1 -ne 39064
then
echo ERROR: fdformat/Makefile checksum is $1 should be 39064
fi
chmod 644 fdformat/Makefile
echo x - fdformat/fdformat.1
sed 's/^@//' >fdformat/fdformat.1 <<'@EOF'
@.\" Copyright (C) 1993, 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.
@.\"
@.Dd September 16, 1993
@.Os
@.Dt FDFORMAT 1
@.Sh NAME
@.Nm fdformat
@.Nd format floppy disks
@.Sh SYNOPSIS
@.Nm fdformat
@.Bq Fl q
@.Bq Fl v
@.Bq Fl n
@.Bq Fl f Ar capacity
@.Bq Fl c Ar cyls
@.Bq Fl s Ar secs
@.Bq Fl h Ar heads
@.br
@.Bq Fl r Ar rate
@.Bq Fl g Ar gap3len
@.Bq Fl i Ar intleave
@.Bq Fl S Ar secshft
@.Bq Fl F Ar fillbyte
@.Bq Fl t Ar steps_per_track
@.Ar device_name
@.Sh DESCRIPTION
@.Nm Fdformat
formats a floppy disk at device
@.Ar device_name .
@.Ar Device_name
should be a character device; it may be given either with a full path
name of a raw device node for a floppy disk drive
@.Pq e.\ g. Pa /dev/rfd0 ,
or default name in an abbreviated form
@.Pq e.\ g. Em fd0 .
In the latter case, the name is constructed by prepending
@.Pa /dev/r
and appending a
@.Em .capacity
to the
@.Ar device_name .
Note that any geometry constraints of the device node
@.Pq minor device number
are meaningless, since they're overridden by
@.Nm fdformat .
@.Pp
The options are as follows:
@.Bl -tag -width 10n -offset indent
@.It Fl q
supress any normal output from the command, and don't ask the
user for a confirmation whether to format the floppy disk at
@.Ar device_name .
@.It Fl f Ar capacity
The normal way to specify the desired formatting parameters.
@.Ar Capacity
is the number of kilobytes to format.
@.It Fl n
Don't verify floppy after formatting.
@.It Fl v
Don't format, verify only.
@.It Fl c Ar cyls
@.It Fl s Ar secs
@.It Fl h Ar heads
@.It Fl r Ar rate
@.It Fl g Ar gap3len
@.It Fl i Ar intleave
@.It Fl S Ar secshft
@.It Fl F Ar fillbyte
@.It Fl t Ar steps_per_track
An alternate method to specify the geometry data to write to the floppy disk.
@.El
If the
@.Fl q
flag has not been specified, the user is asked for a confirmation
of the intended formatting process. In order to continue, an answer
of
@.Dq y
must be given.
@.Sh DIAGNOSTICS
Unless
@.Fl q
has been specified, a single letter is printed to standard output
to inform the user about the progress of work.
First, an
@.Sq Em F
is printed when the track(s) is being formatted, then a
@.Sq Em V
while it's being verified, and if an error has been detected, it
will finally change to
@.Sq Em E .
@.Pp
An exit status of 0 is returned upon successful operation. Exit status
1 is returned on any errors during floppy formatting, and an exit status
of 2 reflects invalid arguments given to the program (along with an
appropriate information written to diagnostic output).
@.Sh SEE ALSO
@.Xr fdc 4 .
@.Sh HISTORY
@.Nm Fdformat
has been developed for 386BSD 0.1
and upgraded to the new
@.Xr fd 4
floppy disk driver. It later became part of the
@.Em FreeBSD
system, release 1.1, and was then ported to NetBSD 1.0.
@.Sh AUTHOR
The program has been contributed by
@.if n Joerg Wunsch,
@.if t J\(:org Wunsch,
Dresden, with changes by Serge Vakulenko and Andrew A. Chernov, Moscow.
@EOF
set `sum $sumopt <fdformat/fdformat.1`; if test $1 -ne 6454
then
echo ERROR: fdformat/fdformat.1 checksum is $1 should be 6454
fi
chmod 444 fdformat/fdformat.1
echo x - fdformat/fdformat.c
cat >fdformat/fdformat.c <<'@EOF'
/*
* 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.
*/
/*
* FreeBSD:
* format a floppy disk
*
* Added FD_GTYPE ioctl, verifying, proportional indicators.
* Serge Vakulenko, vak@zebub.msk.su
* Sat Dec 18 17:45:47 MSK 1993
*
* Final adaptation, change format/verify logic, add separate
* format gap/interleave values
* Andrew A. Chernov, ache@astral.msk.su
* Thu Jan 27 00:47:24 MSK 1994
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <strings.h>
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <machine/ioctl_fd.h>
static void
format_track(int fd, int cyl, int secs, int head, int rate,
int gaplen, int secsize, int fill,int interleave)
{
struct fd_formb f;
register int i,j;
int il[FD_MAX_NSEC + 1];
memset(il,0,sizeof il);
for(j = 0, i = 1; i <= secs; i++) {
while(il[(j%secs)+1]) j++;
il[(j%secs)+1] = i;
j += interleave;
}
f.format_version = FD_FORMAT_VERSION;
f.head = head;
f.cyl = cyl;
f.transfer_rate = rate;
f.fd_formb_secshift = secsize;
f.fd_formb_nsecs = secs;
f.fd_formb_gaplen = gaplen;
f.fd_formb_fillbyte = fill;
for(i = 0; i < secs; i++) {
f.fd_formb_cylno(i) = cyl;
f.fd_formb_headno(i) = head;
f.fd_formb_secno(i) = il[i+1];
f.fd_formb_secsize(i) = secsize;
}
if(ioctl(fd, FD_FORM, (caddr_t)&f) < 0) {
perror("\nfdformat: ioctl(FD_FORM)");
exit(1);
}
}
static int
verify_track(int fd, int track, int tracksize)
{
static char *buf = 0;
static int bufsz = 0;
int fdopts = -1, ofdopts, rv = 0;
if (ioctl(fd, FD_GOPTS, &fdopts) < 0)
perror("warning: ioctl(FD_GOPTS)");
else {
ofdopts = fdopts;
fdopts |= FDOPT_NORETRY;
(void)ioctl(fd, FD_SOPTS, &fdopts);
}
if (bufsz < tracksize) {
if (buf)
free (buf);
bufsz = tracksize;
buf = 0;
}
if (! buf)
buf = malloc (bufsz);
if (! buf) {
fprintf (stderr, "\nfdformat: out of memory\n");
exit (2);
}
if (lseek (fd, (long) track*tracksize, 0) < 0)
rv = -1;
/* try twice reading it, without using the normal retrier */
else if (read (fd, buf, tracksize) != tracksize
&& read (fd, buf, tracksize) != tracksize)
rv = -1;
if(fdopts != -1)
(void)ioctl(fd, FD_SOPTS, &ofdopts);
return (rv);
}
static const char *
makename(const char *arg, const char *suffix)
{
static char namebuff[20]; /* big enough for "/dev/rfd0a"... */
memset(namebuff, 0, 20);
if(*arg == '\0') /* ??? */
return arg;
if(*arg == '/') /* do not convert absolute pathnames */
return arg;
strcpy(namebuff, "/dev/r");
strncat(namebuff, arg, 3);
strcat(namebuff, suffix);
return namebuff;
}
static void
usage (void)
{
printf("Usage:\n\tfdformat [-q] [-n | -v] [-f #] [-c #] [-s #] [-h #]\n");
printf("\t\t [-r #] [-g #] [-i #] [-S #] [-F #] [-t #] devname\n");
printf("Options:\n");
printf("\t-q\tsupress any normal output, don't ask for confirmation\n");
printf("\t-n\tdon't verify floppy after formatting\n");
printf("\t-v\tdon't format, verify only\n");
printf("\t-f #\tspecify desired floppy capacity, in kilobytes;\n");
printf("\t\tvalid choices are 360, 720, 800, 820, 1200, 1440, 1480, 1720\n");
printf("\tdevname\tthe full name of floppy device or in short form fd0, fd1\n");
printf("Obscure options:\n");
printf("\t-c #\tspecify number of cylinders, 40 or 80\n");
printf("\t-s #\tspecify number of sectors per track, 9, 10, 15 or 18\n");
printf("\t-h #\tspecify number of floppy heads, 1 or 2\n");
printf("\t-r #\tspecify data rate, 250, 300 or 500 kbps\n");
printf("\t-g #\tspecify gap length\n");
printf("\t-i #\tspecify interleave factor\n");
printf("\t-S #\tspecify sector size, 0=128, 1=256, 2=512 bytes\n");
printf("\t-F #\tspecify fill byte\n");
printf("\t-t #\tnumber of steps per track\n");
exit(2);
}
static int
yes (void)
{
char reply [256], *p;
reply[sizeof(reply)-1] = 0;
for (;;) {
fflush(stdout);
if (! fgets (reply, sizeof(reply)-1, stdin))
return (0);
for (p=reply; *p==' ' || *p=='\t'; ++p)
continue;
if (*p=='y' || *p=='Y')
return (1);
if (*p=='n' || *p=='N' || *p=='\n' || *p=='\r')
return (0);
printf("Answer `yes' or `no': ");
}
}
int
main(int argc, char **argv)
{
int format = -1, cyls = -1, secs = -1, heads = -1, intleave = -1;
int rate = -1, gaplen = -1, secsize = -1, steps = -1;
int fill = 0xf6, quiet = 0, verify = 1, verify_only = 0;
int fd, c, track, error, tracks_per_dot, bytes_per_track, errs;
const char *devname, *suffix;
struct fd_type fdt;
while((c = getopt(argc, argv, "f:c:s:h:r:g:S:F:t:i:qvn")) != -1)
switch(c) {
case 'f': /* format in kilobytes */
format = atoi(optarg);
break;
case 'c': /* # of cyls */
cyls = atoi(optarg);
break;
case 's': /* # of secs per track */
secs = atoi(optarg);
break;
case 'h': /* # of heads */
heads = atoi(optarg);
break;
case 'r': /* transfer rate, kilobyte/sec */
rate = atoi(optarg);
break;
case 'g': /* length of GAP3 to format with */
gaplen = atoi(optarg);
break;
case 'S': /* sector size shift factor (1 << S)*128 */
secsize = atoi(optarg);
break;
case 'F': /* fill byte, C-like notation allowed */
fill = (int)strtol(optarg, (char **)0, 0);
break;
case 't': /* steps per track */
steps = atoi(optarg);
break;
case 'i': /* interleave factor */
intleave = atoi(optarg);
break;
case 'q':
quiet = 1;
break;
case 'n':
verify = 0;
break;
case 'v':
verify = 1;
verify_only = 1;
break;
case '?': default:
usage();
}
if(optind != argc - 1)
usage();
switch(format) {
default:
fprintf(stderr, "fdformat: bad floppy size: %dK\n", format);
exit(2);
case -1: suffix = ""; break;
case 360: suffix = ".360"; break;
case 720: suffix = ".720"; break;
case 800: suffix = ".800"; break;
case 820: suffix = ".820"; break;
case 1200: suffix = ".1200"; break;
case 1440: suffix = ".1440"; break;
case 1480: suffix = ".1480"; break;
case 1720: suffix = ".1720"; break;
}
devname = makename(argv[optind], suffix);
if((fd = open(devname, O_RDWR)) < 0) {
perror(devname);
exit(1);
}
if(ioctl(fd, FD_GTYPE, &fdt) < 0) {
fprintf(stderr, "fdformat: not a floppy disk: %s\n", devname);
exit(1);
}
switch(rate) {
case -1: break;
case 250: fdt.rate = FDC_250KBPS; break;
case 300: fdt.rate = FDC_300KBPS; break;
case 500: fdt.rate = FDC_500KBPS; break;
default:
fprintf(stderr, "fdformat: invalid transfer rate: %d\n", rate);
exit(2);
}
if (cyls >= 0) fdt.tracks = cyls;
if (secs >= 0) fdt.sectrac = secs;
if (fdt.sectrac > FD_MAX_NSEC) {
fprintf(stderr, "fdformat: too many sectors per track, max value is %d\n", FD_MAX_NSEC);
exit(2);
}
if (heads >= 0) fdt.heads = heads;
if (gaplen >= 0) fdt.gap2 = gaplen;
if (secsize >= 0) fdt.secsize = secsize;
if (steps >= 0) fdt.step = steps;
bytes_per_track = fdt.sectrac * (1<<fdt.secsize) * 128;
tracks_per_dot = fdt.tracks * fdt.heads / 40;
if (verify_only) {
if(!quiet)
printf("Verify %dK floppy `%s'.\n",
fdt.tracks * fdt.heads * bytes_per_track / 1024,
devname);
}
else if(!quiet) {
printf("Format %dK floppy `%s'? (y/n): ",
fdt.tracks * fdt.heads * bytes_per_track / 1024,
devname);
if(! yes ()) {
printf("Not confirmed.\n");
return 0;
}
}
/*
* Formatting.
*/
if(!quiet) {
printf("Processing ----------------------------------------\r");
printf("Processing ");
fflush(stdout);
}
error = errs = 0;
for (track = 0; track < fdt.tracks * fdt.heads; track++) {
if (!verify_only) {
format_track(fd, track / fdt.heads, fdt.sectrac,
track % fdt.heads, fdt.rate, fdt.gap2,
fdt.secsize, fill,
intleave >= 0 ? intleave : 1);
if(!quiet && !((track + 1) % tracks_per_dot)) {
putchar('F');
fflush(stdout);
}
}
if (verify) {
if (verify_track(fd, track, bytes_per_track) < 0)
error = errs = 1;
if(!quiet && !((track + 1) % tracks_per_dot)) {
if (!verify_only)
putchar('\b');
if (error) {
putchar('E');
error = 0;
}
else
putchar('V');
fflush(stdout);
}
}
}
if(!quiet)
printf(" done.\n");
return errs;
}
/*
* Local Variables:
* c-indent-level: 8
* c-continued-statement-offset: 8
* c-continued-brace-offset: 0
* c-brace-offset: -8
* c-brace-imaginary-offset: 0
* c-argdecl-indent: 8
* c-label-offset: -8
* c++-hanging-braces: 1
* c++-access-specifier-offset: -8
* c++-empty-arglist-indent: 8
* c++-friend-offset: 0
* End:
*/
@EOF
set `sum $sumopt <fdformat/fdformat.c`; if test $1 -ne 47452
then
echo ERROR: fdformat/fdformat.c checksum is $1 should be 47452
fi
chmod 444 fdformat/fdformat.c
echo x - fdformat/fdformat-sys-diffs
sed 's/^@//' >fdformat/fdformat-sys-diffs <<'@EOF'
diff -rubw /u2/src/sys/arch/i386/isa/fd.c ./arch/i386/isa/fd.c
--- /u2/src/sys/arch/i386/isa/fd.c Mon Mar 20 02:37:49 1995
+++ ./arch/i386/isa/fd.c Sat Jan 28 16:29:01 1995
@@@ -8,6 +8,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,12 +56,14 @@
#include <sys/dkstat.h>
#include <sys/disk.h>
#include <sys/buf.h>
+#include <sys/malloc.h>
#include <sys/uio.h>
#include <sys/syslog.h>
#include <sys/queue.h>
#include <machine/cpu.h>
#include <machine/pio.h>
+#include <machine/ioctl_fd.h>
#include <i386/isa/isavar.h>
#include <i386/isa/dmavar.h>
@@@ -69,6 +77,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 {
@@@ -117,25 +128,7 @@
NULL, "fdc", fdcprobe, fdcattach, DV_DULL, sizeof(struct fdc_softc)
};
-/*
- * 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[] = {
@@@ -158,6 +151,7 @@
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 */
@@@ -202,6 +196,7 @@
int fdcintr __P((struct fdc_softc *));
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 *));
int
fdcprobe(parent, match, aux)
@@@ -482,7 +477,8 @@
if (unit >= fdcd.cd_ndevs ||
(fd = fdcd.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;
}
@@@ -716,6 +712,7 @@
struct fd_softc *fd = fdcd.cd_devs[FDUNIT(dev)];
fd->sc_flags &= ~FD_OPEN;
+ fd->sc_opts &= ~FDOPT_NORETRY;
return 0;
}
@@@ -785,6 +782,9 @@
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)
@@@ -820,6 +820,7 @@
int iobase = fdc->sc_iobase;
int read, head, trac, sec, i, s, nblks;
struct fd_type *type;
+ struct fd_formb *finfo = NULL;
loop:
/* Is there a drive for the controller to do a transfer with? */
@@@ -838,6 +839,9 @@
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;
@@@ -888,12 +892,15 @@
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
@@@ -920,6 +927,19 @@
read ? "read" : "write", fd->sc_drive, fd->sc_cylin, head,
sec, nblks);
#endif
+ if (finfo) {
+ /* formatting */
+ if (out_fdc(iobase, NE7CMD_FORMAT) < 0) {
+ fdc->sc_errors = 4;
+ fdcretry(fdc);
+ goto loop;
+ }
+ out_fdc(iobase, (head << 2) | fd->sc_drive);
+ out_fdc(iobase, finfo->fd_formb_secshift);
+ out_fdc(iobase, finfo->fd_formb_nsecs);
+ out_fdc(iobase, finfo->fd_formb_gaplen);
+ out_fdc(iobase, finfo->fd_formb_fillbyte);
+ } else {
if (read)
out_fdc(iobase, NE7CMD_READ); /* READ */
else
@@@ -932,6 +952,7 @@
out_fdc(iobase, type->sectrac); /* sectors/track */
out_fdc(iobase, type->gap1); /* gap1 size */
out_fdc(iobase, type->datalen); /* data length */
+ }
fdc->sc_state = IOCOMPLETE;
/* allow 2 seconds for operation */
timeout(fdctimeout, fdc, 2 * hz);
@@@ -1003,7 +1024,7 @@
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;
}
@@@ -1080,6 +1101,8 @@
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 */
@@@ -1097,6 +1120,7 @@
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",
@@@ -1130,11 +1154,12 @@
}
int
-fdioctl(dev, cmd, addr, flag)
+fdioctl(dev, cmd, addr, flag, p)
dev_t dev;
u_long cmd;
caddr_t addr;
int flag;
+ struct proc *p;
{
struct fd_softc *fd = fdcd.cd_devs[FDUNIT(dev)];
struct disklabel buffer;
@@@ -1171,6 +1196,28 @@
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;
}
@@@ -1178,4 +1225,64 @@
#ifdef DIAGNOSTIC
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 = fdcd.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 -rubw /dev/null ./arch/i386/include/ioctl_fd.h
--- /dev/null Thu Apr 6 18:28:33 1995
+++ ./arch/i386/include/ioctl_fd.h Sat Jan 28 16:58:23 1995
@@@ -0,0 +1,130 @@
+/* $Id: ioctl_fd.h,v 1.3 1995/01/28 21:58:20 jtk 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 FD_DEBUG _IOW('F', 66, 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__ */
@EOF
set `sum $sumopt <fdformat/fdformat-sys-diffs`; if test $1 -ne 2398
then
echo ERROR: fdformat/fdformat-sys-diffs checksum is $1 should be 2398
fi
chmod 664 fdformat/fdformat-sys-diffs
chmod 775 fdformat
exit 0
--
John Kohl <jtk@atria.com> or <jtkohl@mit.edu>
working for but not representing: Atria Software
sometimes hacking on: NetBSD/i386