diff options
author | Jason Downs <downsj@cvs.openbsd.org> | 1996-06-20 07:51:38 +0000 |
---|---|---|
committer | Jason Downs <downsj@cvs.openbsd.org> | 1996-06-20 07:51:38 +0000 |
commit | f891a2d378fd94e732b4f03fdb5340c1a458eb89 (patch) | |
tree | 7439f1fe76b0367705ada4089b059b3b0a895cf3 | |
parent | 95ed63a1d6fd46db236abe4f3d88fc550654e628 (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.h | 129 | ||||
-rw-r--r-- | sys/arch/i386/isa/fd.c | 176 | ||||
-rw-r--r-- | sys/dev/isa/fd.c | 176 |
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; +} |