From 5d04c702eb0d8e65b637b3212bf3b5073f541e7b Mon Sep 17 00:00:00 2001 From: Joerg Wunsch Date: Sun, 30 Oct 1994 20:04:40 +0000 Subject: [PATCH] Several minor fixes to the floppy driver: . avoid resetting the FDC every time the last motor is going off; instead, give it a 60-second period for possible later reactivation. This prevents us from needing to recalibrate the FDC too often, but still allows for an ``automagic error recovery', just in case the controller is absolutely stuck. (Simply wait for 60 seconds, and try it again.) . made the floppy head settle time after a seek a constant that might be overridden by a config option. (Well, actually the divisor of the settle time). Pepople often reported problems with their floppies, so i need a simply mechanism that allows them to play with that value. (I personally cannot find any problem on *my* drives.) . implement the FD_DEBUG ioctl command, in case the driver is compiled with DEBUG turned on. . removed a bogus parameter from a printf; the remaining warnings from gcc -Wall seem to be warnings about the %b format gcc cannot understand . rearrange Garett's code to fit better in the existing structure of #define/type/function ordering. . make everything fit into 79 columns again. --- sys/dev/fdc/fdc.c | 243 +++++++++++++++++++++++++++------------------- sys/i386/isa/fd.c | 243 +++++++++++++++++++++++++++------------------- sys/isa/fd.c | 243 +++++++++++++++++++++++++++------------------- 3 files changed, 432 insertions(+), 297 deletions(-) diff --git a/sys/dev/fdc/fdc.c b/sys/dev/fdc/fdc.c index e06ac4aab450..3883fd3c0cf5 100644 --- a/sys/dev/fdc/fdc.c +++ b/sys/dev/fdc/fdc.c @@ -40,7 +40,7 @@ * SUCH DAMAGE. * * from: @(#)fd.c 7.4 (Berkeley) 5/25/91 - * $Id: fd.c,v 1.37 1994/10/23 21:27:12 wollman Exp $ + * $Id: fd.c,v 1.38 1994/10/27 20:44:46 jkh Exp $ * */ @@ -80,74 +80,8 @@ static int fd_goaway(struct kern_devconf *, int); static int fdc_goaway(struct kern_devconf *, int); -static int fd_externalize(struct proc *, struct kern_devconf *, void *, size_t); - -/* - * Templates for the kern_devconf structures used when we attach. - */ -static struct kern_devconf kdc_fd[NFD] = { { - 0, 0, 0, /* filled in by kern_devconf.c */ - "fd", 0, { MDDT_DISK, 0 }, - fd_externalize, 0, fd_goaway, DISK_EXTERNALLEN, - 0, /* parent */ - 0, /* parentdata */ - DC_UNKNOWN, /* state */ - "floppy disk" -} }; - -struct kern_devconf kdc_fdc[NFDC] = { { - 0, 0, 0, /* filled in by kern_devconf.c */ - "fdc", 0, { MDDT_ISA, 0, "bio" }, - isa_generic_externalize, 0, fdc_goaway, ISA_EXTERNALLEN, - 0, /* parent */ - 0, /* parentdata */ - DC_UNKNOWN, /* state */ - "floppy disk/tape controller" -} }; - -static inline void -fd_registerdev(int ctlr, int unit) -{ - if(unit != 0) - kdc_fd[unit] = kdc_fd[0]; - - kdc_fd[unit].kdc_unit = unit; - kdc_fd[unit].kdc_parent = &kdc_fdc[ctlr]; - kdc_fd[unit].kdc_parentdata = 0; - dev_attach(&kdc_fd[unit]); -} - -static inline void -fdc_registerdev(struct isa_device *dvp) -{ - int unit = dvp->id_unit; - - if(unit != 0) - kdc_fdc[unit] = kdc_fdc[0]; - - kdc_fdc[unit].kdc_unit = unit; - kdc_fdc[unit].kdc_parent = &kdc_isa0; - kdc_fdc[unit].kdc_parentdata = dvp; - dev_attach(&kdc_fdc[unit]); -} - -static int -fdc_goaway(struct kern_devconf *kdc, int force) -{ - if(force) { - dev_detach(kdc); - return 0; - } else { - return EBUSY; /* XXX fix */ - } -} - -static int -fd_goaway(struct kern_devconf *kdc, int force) -{ - dev_detach(kdc); - return 0; -} +static int fd_externalize(struct proc *, struct kern_devconf *, + void *, size_t); #define RAW_PART 2 #define b_cylin b_resid @@ -155,6 +89,17 @@ fd_goaway(struct kern_devconf *kdc, int force) /* misuse a flag to identify format operation */ #define B_FORMAT B_XXX +/* + * Since several people happen to have problems with their drives, + * it might be a good idea to allow a config file override for the + * floppy seek settle time; the value is in 1s / FDSEEKWAIT; + * Preferrable values are powers of two, since the compiler can + * replace the divide operations by simple shifts then! + */ +#ifndef FDSEEKWAIT +# define FDSEEKWAIT 16 /* has been 32 in FreeBSD 1.1.5.1 */ +#endif + /* * this biotab field doubles as a field for the physical unit number * on the controller @@ -323,17 +268,87 @@ int fd_debug = 0; struct isa_device *fdcdevs[NFDC]; + +/* + * Templates for the kern_devconf structures used when we attach. + */ +static struct kern_devconf kdc_fd[NFD] = { { + 0, 0, 0, /* filled in by kern_devconf.c */ + "fd", 0, { MDDT_DISK, 0 }, + fd_externalize, 0, fd_goaway, DISK_EXTERNALLEN, + 0, /* parent */ + 0, /* parentdata */ + DC_UNKNOWN, /* state */ + "floppy disk" +} }; + +struct kern_devconf kdc_fdc[NFDC] = { { + 0, 0, 0, /* filled in by kern_devconf.c */ + "fdc", 0, { MDDT_ISA, 0, "bio" }, + isa_generic_externalize, 0, fdc_goaway, ISA_EXTERNALLEN, + 0, /* parent */ + 0, /* parentdata */ + DC_UNKNOWN, /* state */ + "floppy disk/tape controller" +} }; + +static inline void +fd_registerdev(int ctlr, int unit) +{ + if(unit != 0) + kdc_fd[unit] = kdc_fd[0]; + + kdc_fd[unit].kdc_unit = unit; + kdc_fd[unit].kdc_parent = &kdc_fdc[ctlr]; + kdc_fd[unit].kdc_parentdata = 0; + dev_attach(&kdc_fd[unit]); +} + +static inline void +fdc_registerdev(struct isa_device *dvp) +{ + int unit = dvp->id_unit; + + if(unit != 0) + kdc_fdc[unit] = kdc_fdc[0]; + + kdc_fdc[unit].kdc_unit = unit; + kdc_fdc[unit].kdc_parent = &kdc_isa0; + kdc_fdc[unit].kdc_parentdata = dvp; + dev_attach(&kdc_fdc[unit]); +} + +static int +fdc_goaway(struct kern_devconf *kdc, int force) +{ + if(force) { + dev_detach(kdc); + return 0; + } else { + return EBUSY; /* XXX fix */ + } +} + +static int +fd_goaway(struct kern_devconf *kdc, int force) +{ + dev_detach(kdc); + return 0; +} + /* * Provide hw.devconf information. */ static int -fd_externalize(struct proc *p, struct kern_devconf *kdc, void *userp, size_t len) +fd_externalize(struct proc *p, struct kern_devconf *kdc, void *userp, + size_t len) { return disk_externalize(fd_data[kdc->kdc_unit].fdsu, userp, &len); } static int -fdc_externalize(struct proc *p, struct kern_devconf *kdc, void *userp, size_t len) +fdc_externalize(struct proc *p, struct kern_devconf *kdc, void *userp, + size_t len) { return isa_externalize(fdcdevs[kdc->kdc_unit], userp, &len); } @@ -529,10 +544,30 @@ fdsize(dev) return(0); } + /****************************************************************************/ /* motor control stuff */ -/* remember to not deselect the drive we're working on */ /****************************************************************************/ + +static void +fdc_gotobed(void *arg1) +{ + int fdcu = (int)arg1; + int fdout = fdc_data[fdcu].fdout; + + if((fdout & FDO_FRST) == 0) + /* huh? */ + return; + + /* reset controller */ + fdout &= ~ (FDO_FRST|FDO_FDMAEN); + + outb(fdc_data[fdcu].baseport+FDOUT, fdout); + fdc_data[fdcu].fdout = fdout; + TRACE1("[0x%x->FDOUT]", fdout); +} + + static void set_motor(fdcu, fdsu, turnon) fdcu_t fdcu; @@ -541,22 +576,31 @@ set_motor(fdcu, fdsu, turnon) { int fdout = fdc_data[fdcu].fdout; int needspecify = 0; + int x; + /* if a timeout is almost due, avoid killing the FDC */ + x = splsoftclock(); if(turnon) { + if((fdout & (FDO_FRST|FDO_FDMAEN))) + untimeout(fdc_gotobed, (void *)fdcu); fdout &= ~FDO_FDSEL; fdout |= (FDO_MOEN0 << fdsu) + fdsu; } else fdout &= ~(FDO_MOEN0 << fdsu); + splx(x); - if(!turnon - && (fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0) - /* gonna turn off the last drive, put FDC to bed */ - fdout &= ~ (FDO_FRST|FDO_FDMAEN); - else { + if(turnon) { /* make sure controller is selected and specified */ if((fdout & (FDO_FRST|FDO_FDMAEN)) == 0) needspecify = 1; fdout |= (FDO_FRST|FDO_FDMAEN); + } else { + if((fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0) + /* + * gonna turn off the last drive, schedule a timeout + * to put the FDC to bed later (just for sanity) + */ + timeout(fdc_gotobed, (void *)fdcu, hz * 60); } outb(fdc_data[fdcu].baseport+FDOUT, fdout); @@ -572,10 +616,10 @@ set_motor(fdcu, fdsu, turnon) out_fdc(fdcu, NE7CMD_SPECIFY); out_fdc(fdcu, NE7_SPEC_1(3, 240)); out_fdc(fdcu, NE7_SPEC_2(2, 0)); + fdc_data[fdcu].state = STARTRECAL; /* need to recalib now */ } } -/* ARGSUSED */ static void fd_turnoff(void *arg1) { @@ -589,7 +633,6 @@ fd_turnoff(void *arg1) splx(s); } -/* ARGSUSED */ static void fd_motor_on(void *arg1) { @@ -615,7 +658,7 @@ fd_turnon(fdu) { fd->flags |= (FD_MOTOR + FD_MOTOR_WAIT); set_motor(fd->fdc->fdcu, fd->fdsu, TURNON); - timeout(fd_motor_on, (caddr_t)fdu, hz); /* in 1 sec its ok */ + timeout(fd_motor_on, (void *)fdu, hz); /* in 1 sec its ok */ } } @@ -857,7 +900,7 @@ fdstrategy(struct buf *bp) dp = &(fdc->head); s = splbio(); disksort(dp, bp); - untimeout(fd_turnoff, (caddr_t)fdu); /* a good idea */ + untimeout(fd_turnoff, (void *)fdu); /* a good idea */ fdstart(fdcu); splx(s); return; @@ -889,7 +932,6 @@ fdstart(fdcu) splx(s); } -/* ARGSUSED */ static void fd_timeout(void *arg1) { @@ -941,7 +983,6 @@ fd_timeout(void *arg1) } /* just ensure it has the right spl */ -/* ARGSUSED */ static void fd_pseudointr(void *arg1) { @@ -1023,8 +1064,8 @@ fdstate(fdcu, fdc) TRACE1("fd%d", fdu); TRACE1("[%s]", fdstates[fdc->state]); TRACE1("(0x%x)", fd->flags); - untimeout(fd_turnoff, (caddr_t)fdu); - timeout(fd_turnoff, (caddr_t)fdu, 4 * hz); + untimeout(fd_turnoff, (void *)fdu); + timeout(fd_turnoff, (void *)fdu, 4 * hz); switch (fdc->state) { case DEVIDLE: @@ -1055,9 +1096,9 @@ fdstate(fdcu, fdc) } else /* at least make sure we are selected */ { + fdc->state = DOSEEK; set_motor(fdcu, fd->fdsu, TURNON); } - fdc->state = DOSEEK; break; case DOSEEK: if (bp->b_cylin == fd->track) @@ -1081,7 +1122,7 @@ fdstate(fdcu, fdc) return(0); /* will return later */ case SEEKWAIT: /* allow heads to settle */ - timeout(fd_pseudointr, (caddr_t)fdcu, hz / 32); + timeout(fd_pseudointr, (void *)fdcu, hz / FDSEEKWAIT); fdc->state = SEEKCOMPLETE; return(0); /* will return later */ case SEEKCOMPLETE : /* SEEK DONE, START DMA */ @@ -1121,7 +1162,7 @@ fdstate(fdcu, fdc) { printf( "fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n", - fdu, descyl, cyl, st0, NE7_ST0BITS); + fdu, descyl, cyl, st0); return(retrier(fdcu)); } } @@ -1207,10 +1248,10 @@ fdstate(fdcu, fdc) out_fdc(fdcu, fd->ft->datalen); /* data length */ } fdc->state = IOCOMPLETE; - timeout(fd_timeout, (caddr_t)fdcu, hz); + timeout(fd_timeout, (void *)fdcu, hz); return(0); /* will return later */ case IOCOMPLETE: /* IO DONE, post-analyze */ - untimeout(fd_timeout, (caddr_t)fdcu); + untimeout(fd_timeout, (void *)fdcu); for(i=0;i<7;i++) { fdc->status[i] = in_fdc(fdcu); @@ -1283,7 +1324,7 @@ fdstate(fdcu, fdc) return(0); /* will return later */ case RECALWAIT: /* allow heads to settle */ - timeout(fd_pseudointr, (caddr_t)fdcu, hz / 32); + timeout(fd_pseudointr, (void *)fdcu, hz / FDSEEKWAIT); fdc->state = RECALCOMPLETE; return(0); /* will return later */ case RECALCOMPLETE: @@ -1322,12 +1363,7 @@ fdstate(fdcu, fdc) { return(0); /* time's not up yet */ } - /* - * since the controller was off, it has lost its - * idea about the current track it were; thus, - * recalibrate the bastard - */ - fdc->state = STARTRECAL; + fdc->state = DOSEEK; return(1); /* will return immediatly */ default: printf("Unexpected FD int->"); @@ -1452,7 +1488,7 @@ fdformat(dev, finfo, p) + finfo->head * fd->ft->sectrac) * fdblk / DEV_BSIZE; bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; - bp->b_un.b_addr = (caddr_t)finfo; + bp->b_un.b_addr = (void *)finfo; /* now do the format */ fdstrategy(bp); @@ -1461,7 +1497,7 @@ fdformat(dev, finfo, p) s = splbio(); while(!(bp->b_flags & B_DONE)) { - rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz); + rv = tsleep((void *)bp, PRIBIO, "fdform", 20 * hz); if(rv == EWOULDBLOCK) break; } @@ -1586,6 +1622,15 @@ fdioctl(dev, cmd, addr, flag, p) fd_data[FDUNIT(minor(dev))].options = *(int *)addr; break; +#ifdef DEBUG + case FD_DEBUG: + /* this is considered harmful; only allow for superuser */ + if(suser(p->p_ucred, &p->p_acflag) != 0) + return EPERM; + fd_debug = *(int *)addr; + break; +#endif + default: error = ENOTTY; break; diff --git a/sys/i386/isa/fd.c b/sys/i386/isa/fd.c index e06ac4aab450..3883fd3c0cf5 100644 --- a/sys/i386/isa/fd.c +++ b/sys/i386/isa/fd.c @@ -40,7 +40,7 @@ * SUCH DAMAGE. * * from: @(#)fd.c 7.4 (Berkeley) 5/25/91 - * $Id: fd.c,v 1.37 1994/10/23 21:27:12 wollman Exp $ + * $Id: fd.c,v 1.38 1994/10/27 20:44:46 jkh Exp $ * */ @@ -80,74 +80,8 @@ static int fd_goaway(struct kern_devconf *, int); static int fdc_goaway(struct kern_devconf *, int); -static int fd_externalize(struct proc *, struct kern_devconf *, void *, size_t); - -/* - * Templates for the kern_devconf structures used when we attach. - */ -static struct kern_devconf kdc_fd[NFD] = { { - 0, 0, 0, /* filled in by kern_devconf.c */ - "fd", 0, { MDDT_DISK, 0 }, - fd_externalize, 0, fd_goaway, DISK_EXTERNALLEN, - 0, /* parent */ - 0, /* parentdata */ - DC_UNKNOWN, /* state */ - "floppy disk" -} }; - -struct kern_devconf kdc_fdc[NFDC] = { { - 0, 0, 0, /* filled in by kern_devconf.c */ - "fdc", 0, { MDDT_ISA, 0, "bio" }, - isa_generic_externalize, 0, fdc_goaway, ISA_EXTERNALLEN, - 0, /* parent */ - 0, /* parentdata */ - DC_UNKNOWN, /* state */ - "floppy disk/tape controller" -} }; - -static inline void -fd_registerdev(int ctlr, int unit) -{ - if(unit != 0) - kdc_fd[unit] = kdc_fd[0]; - - kdc_fd[unit].kdc_unit = unit; - kdc_fd[unit].kdc_parent = &kdc_fdc[ctlr]; - kdc_fd[unit].kdc_parentdata = 0; - dev_attach(&kdc_fd[unit]); -} - -static inline void -fdc_registerdev(struct isa_device *dvp) -{ - int unit = dvp->id_unit; - - if(unit != 0) - kdc_fdc[unit] = kdc_fdc[0]; - - kdc_fdc[unit].kdc_unit = unit; - kdc_fdc[unit].kdc_parent = &kdc_isa0; - kdc_fdc[unit].kdc_parentdata = dvp; - dev_attach(&kdc_fdc[unit]); -} - -static int -fdc_goaway(struct kern_devconf *kdc, int force) -{ - if(force) { - dev_detach(kdc); - return 0; - } else { - return EBUSY; /* XXX fix */ - } -} - -static int -fd_goaway(struct kern_devconf *kdc, int force) -{ - dev_detach(kdc); - return 0; -} +static int fd_externalize(struct proc *, struct kern_devconf *, + void *, size_t); #define RAW_PART 2 #define b_cylin b_resid @@ -155,6 +89,17 @@ fd_goaway(struct kern_devconf *kdc, int force) /* misuse a flag to identify format operation */ #define B_FORMAT B_XXX +/* + * Since several people happen to have problems with their drives, + * it might be a good idea to allow a config file override for the + * floppy seek settle time; the value is in 1s / FDSEEKWAIT; + * Preferrable values are powers of two, since the compiler can + * replace the divide operations by simple shifts then! + */ +#ifndef FDSEEKWAIT +# define FDSEEKWAIT 16 /* has been 32 in FreeBSD 1.1.5.1 */ +#endif + /* * this biotab field doubles as a field for the physical unit number * on the controller @@ -323,17 +268,87 @@ int fd_debug = 0; struct isa_device *fdcdevs[NFDC]; + +/* + * Templates for the kern_devconf structures used when we attach. + */ +static struct kern_devconf kdc_fd[NFD] = { { + 0, 0, 0, /* filled in by kern_devconf.c */ + "fd", 0, { MDDT_DISK, 0 }, + fd_externalize, 0, fd_goaway, DISK_EXTERNALLEN, + 0, /* parent */ + 0, /* parentdata */ + DC_UNKNOWN, /* state */ + "floppy disk" +} }; + +struct kern_devconf kdc_fdc[NFDC] = { { + 0, 0, 0, /* filled in by kern_devconf.c */ + "fdc", 0, { MDDT_ISA, 0, "bio" }, + isa_generic_externalize, 0, fdc_goaway, ISA_EXTERNALLEN, + 0, /* parent */ + 0, /* parentdata */ + DC_UNKNOWN, /* state */ + "floppy disk/tape controller" +} }; + +static inline void +fd_registerdev(int ctlr, int unit) +{ + if(unit != 0) + kdc_fd[unit] = kdc_fd[0]; + + kdc_fd[unit].kdc_unit = unit; + kdc_fd[unit].kdc_parent = &kdc_fdc[ctlr]; + kdc_fd[unit].kdc_parentdata = 0; + dev_attach(&kdc_fd[unit]); +} + +static inline void +fdc_registerdev(struct isa_device *dvp) +{ + int unit = dvp->id_unit; + + if(unit != 0) + kdc_fdc[unit] = kdc_fdc[0]; + + kdc_fdc[unit].kdc_unit = unit; + kdc_fdc[unit].kdc_parent = &kdc_isa0; + kdc_fdc[unit].kdc_parentdata = dvp; + dev_attach(&kdc_fdc[unit]); +} + +static int +fdc_goaway(struct kern_devconf *kdc, int force) +{ + if(force) { + dev_detach(kdc); + return 0; + } else { + return EBUSY; /* XXX fix */ + } +} + +static int +fd_goaway(struct kern_devconf *kdc, int force) +{ + dev_detach(kdc); + return 0; +} + /* * Provide hw.devconf information. */ static int -fd_externalize(struct proc *p, struct kern_devconf *kdc, void *userp, size_t len) +fd_externalize(struct proc *p, struct kern_devconf *kdc, void *userp, + size_t len) { return disk_externalize(fd_data[kdc->kdc_unit].fdsu, userp, &len); } static int -fdc_externalize(struct proc *p, struct kern_devconf *kdc, void *userp, size_t len) +fdc_externalize(struct proc *p, struct kern_devconf *kdc, void *userp, + size_t len) { return isa_externalize(fdcdevs[kdc->kdc_unit], userp, &len); } @@ -529,10 +544,30 @@ fdsize(dev) return(0); } + /****************************************************************************/ /* motor control stuff */ -/* remember to not deselect the drive we're working on */ /****************************************************************************/ + +static void +fdc_gotobed(void *arg1) +{ + int fdcu = (int)arg1; + int fdout = fdc_data[fdcu].fdout; + + if((fdout & FDO_FRST) == 0) + /* huh? */ + return; + + /* reset controller */ + fdout &= ~ (FDO_FRST|FDO_FDMAEN); + + outb(fdc_data[fdcu].baseport+FDOUT, fdout); + fdc_data[fdcu].fdout = fdout; + TRACE1("[0x%x->FDOUT]", fdout); +} + + static void set_motor(fdcu, fdsu, turnon) fdcu_t fdcu; @@ -541,22 +576,31 @@ set_motor(fdcu, fdsu, turnon) { int fdout = fdc_data[fdcu].fdout; int needspecify = 0; + int x; + /* if a timeout is almost due, avoid killing the FDC */ + x = splsoftclock(); if(turnon) { + if((fdout & (FDO_FRST|FDO_FDMAEN))) + untimeout(fdc_gotobed, (void *)fdcu); fdout &= ~FDO_FDSEL; fdout |= (FDO_MOEN0 << fdsu) + fdsu; } else fdout &= ~(FDO_MOEN0 << fdsu); + splx(x); - if(!turnon - && (fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0) - /* gonna turn off the last drive, put FDC to bed */ - fdout &= ~ (FDO_FRST|FDO_FDMAEN); - else { + if(turnon) { /* make sure controller is selected and specified */ if((fdout & (FDO_FRST|FDO_FDMAEN)) == 0) needspecify = 1; fdout |= (FDO_FRST|FDO_FDMAEN); + } else { + if((fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0) + /* + * gonna turn off the last drive, schedule a timeout + * to put the FDC to bed later (just for sanity) + */ + timeout(fdc_gotobed, (void *)fdcu, hz * 60); } outb(fdc_data[fdcu].baseport+FDOUT, fdout); @@ -572,10 +616,10 @@ set_motor(fdcu, fdsu, turnon) out_fdc(fdcu, NE7CMD_SPECIFY); out_fdc(fdcu, NE7_SPEC_1(3, 240)); out_fdc(fdcu, NE7_SPEC_2(2, 0)); + fdc_data[fdcu].state = STARTRECAL; /* need to recalib now */ } } -/* ARGSUSED */ static void fd_turnoff(void *arg1) { @@ -589,7 +633,6 @@ fd_turnoff(void *arg1) splx(s); } -/* ARGSUSED */ static void fd_motor_on(void *arg1) { @@ -615,7 +658,7 @@ fd_turnon(fdu) { fd->flags |= (FD_MOTOR + FD_MOTOR_WAIT); set_motor(fd->fdc->fdcu, fd->fdsu, TURNON); - timeout(fd_motor_on, (caddr_t)fdu, hz); /* in 1 sec its ok */ + timeout(fd_motor_on, (void *)fdu, hz); /* in 1 sec its ok */ } } @@ -857,7 +900,7 @@ fdstrategy(struct buf *bp) dp = &(fdc->head); s = splbio(); disksort(dp, bp); - untimeout(fd_turnoff, (caddr_t)fdu); /* a good idea */ + untimeout(fd_turnoff, (void *)fdu); /* a good idea */ fdstart(fdcu); splx(s); return; @@ -889,7 +932,6 @@ fdstart(fdcu) splx(s); } -/* ARGSUSED */ static void fd_timeout(void *arg1) { @@ -941,7 +983,6 @@ fd_timeout(void *arg1) } /* just ensure it has the right spl */ -/* ARGSUSED */ static void fd_pseudointr(void *arg1) { @@ -1023,8 +1064,8 @@ fdstate(fdcu, fdc) TRACE1("fd%d", fdu); TRACE1("[%s]", fdstates[fdc->state]); TRACE1("(0x%x)", fd->flags); - untimeout(fd_turnoff, (caddr_t)fdu); - timeout(fd_turnoff, (caddr_t)fdu, 4 * hz); + untimeout(fd_turnoff, (void *)fdu); + timeout(fd_turnoff, (void *)fdu, 4 * hz); switch (fdc->state) { case DEVIDLE: @@ -1055,9 +1096,9 @@ fdstate(fdcu, fdc) } else /* at least make sure we are selected */ { + fdc->state = DOSEEK; set_motor(fdcu, fd->fdsu, TURNON); } - fdc->state = DOSEEK; break; case DOSEEK: if (bp->b_cylin == fd->track) @@ -1081,7 +1122,7 @@ fdstate(fdcu, fdc) return(0); /* will return later */ case SEEKWAIT: /* allow heads to settle */ - timeout(fd_pseudointr, (caddr_t)fdcu, hz / 32); + timeout(fd_pseudointr, (void *)fdcu, hz / FDSEEKWAIT); fdc->state = SEEKCOMPLETE; return(0); /* will return later */ case SEEKCOMPLETE : /* SEEK DONE, START DMA */ @@ -1121,7 +1162,7 @@ fdstate(fdcu, fdc) { printf( "fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n", - fdu, descyl, cyl, st0, NE7_ST0BITS); + fdu, descyl, cyl, st0); return(retrier(fdcu)); } } @@ -1207,10 +1248,10 @@ fdstate(fdcu, fdc) out_fdc(fdcu, fd->ft->datalen); /* data length */ } fdc->state = IOCOMPLETE; - timeout(fd_timeout, (caddr_t)fdcu, hz); + timeout(fd_timeout, (void *)fdcu, hz); return(0); /* will return later */ case IOCOMPLETE: /* IO DONE, post-analyze */ - untimeout(fd_timeout, (caddr_t)fdcu); + untimeout(fd_timeout, (void *)fdcu); for(i=0;i<7;i++) { fdc->status[i] = in_fdc(fdcu); @@ -1283,7 +1324,7 @@ fdstate(fdcu, fdc) return(0); /* will return later */ case RECALWAIT: /* allow heads to settle */ - timeout(fd_pseudointr, (caddr_t)fdcu, hz / 32); + timeout(fd_pseudointr, (void *)fdcu, hz / FDSEEKWAIT); fdc->state = RECALCOMPLETE; return(0); /* will return later */ case RECALCOMPLETE: @@ -1322,12 +1363,7 @@ fdstate(fdcu, fdc) { return(0); /* time's not up yet */ } - /* - * since the controller was off, it has lost its - * idea about the current track it were; thus, - * recalibrate the bastard - */ - fdc->state = STARTRECAL; + fdc->state = DOSEEK; return(1); /* will return immediatly */ default: printf("Unexpected FD int->"); @@ -1452,7 +1488,7 @@ fdformat(dev, finfo, p) + finfo->head * fd->ft->sectrac) * fdblk / DEV_BSIZE; bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; - bp->b_un.b_addr = (caddr_t)finfo; + bp->b_un.b_addr = (void *)finfo; /* now do the format */ fdstrategy(bp); @@ -1461,7 +1497,7 @@ fdformat(dev, finfo, p) s = splbio(); while(!(bp->b_flags & B_DONE)) { - rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz); + rv = tsleep((void *)bp, PRIBIO, "fdform", 20 * hz); if(rv == EWOULDBLOCK) break; } @@ -1586,6 +1622,15 @@ fdioctl(dev, cmd, addr, flag, p) fd_data[FDUNIT(minor(dev))].options = *(int *)addr; break; +#ifdef DEBUG + case FD_DEBUG: + /* this is considered harmful; only allow for superuser */ + if(suser(p->p_ucred, &p->p_acflag) != 0) + return EPERM; + fd_debug = *(int *)addr; + break; +#endif + default: error = ENOTTY; break; diff --git a/sys/isa/fd.c b/sys/isa/fd.c index e06ac4aab450..3883fd3c0cf5 100644 --- a/sys/isa/fd.c +++ b/sys/isa/fd.c @@ -40,7 +40,7 @@ * SUCH DAMAGE. * * from: @(#)fd.c 7.4 (Berkeley) 5/25/91 - * $Id: fd.c,v 1.37 1994/10/23 21:27:12 wollman Exp $ + * $Id: fd.c,v 1.38 1994/10/27 20:44:46 jkh Exp $ * */ @@ -80,74 +80,8 @@ static int fd_goaway(struct kern_devconf *, int); static int fdc_goaway(struct kern_devconf *, int); -static int fd_externalize(struct proc *, struct kern_devconf *, void *, size_t); - -/* - * Templates for the kern_devconf structures used when we attach. - */ -static struct kern_devconf kdc_fd[NFD] = { { - 0, 0, 0, /* filled in by kern_devconf.c */ - "fd", 0, { MDDT_DISK, 0 }, - fd_externalize, 0, fd_goaway, DISK_EXTERNALLEN, - 0, /* parent */ - 0, /* parentdata */ - DC_UNKNOWN, /* state */ - "floppy disk" -} }; - -struct kern_devconf kdc_fdc[NFDC] = { { - 0, 0, 0, /* filled in by kern_devconf.c */ - "fdc", 0, { MDDT_ISA, 0, "bio" }, - isa_generic_externalize, 0, fdc_goaway, ISA_EXTERNALLEN, - 0, /* parent */ - 0, /* parentdata */ - DC_UNKNOWN, /* state */ - "floppy disk/tape controller" -} }; - -static inline void -fd_registerdev(int ctlr, int unit) -{ - if(unit != 0) - kdc_fd[unit] = kdc_fd[0]; - - kdc_fd[unit].kdc_unit = unit; - kdc_fd[unit].kdc_parent = &kdc_fdc[ctlr]; - kdc_fd[unit].kdc_parentdata = 0; - dev_attach(&kdc_fd[unit]); -} - -static inline void -fdc_registerdev(struct isa_device *dvp) -{ - int unit = dvp->id_unit; - - if(unit != 0) - kdc_fdc[unit] = kdc_fdc[0]; - - kdc_fdc[unit].kdc_unit = unit; - kdc_fdc[unit].kdc_parent = &kdc_isa0; - kdc_fdc[unit].kdc_parentdata = dvp; - dev_attach(&kdc_fdc[unit]); -} - -static int -fdc_goaway(struct kern_devconf *kdc, int force) -{ - if(force) { - dev_detach(kdc); - return 0; - } else { - return EBUSY; /* XXX fix */ - } -} - -static int -fd_goaway(struct kern_devconf *kdc, int force) -{ - dev_detach(kdc); - return 0; -} +static int fd_externalize(struct proc *, struct kern_devconf *, + void *, size_t); #define RAW_PART 2 #define b_cylin b_resid @@ -155,6 +89,17 @@ fd_goaway(struct kern_devconf *kdc, int force) /* misuse a flag to identify format operation */ #define B_FORMAT B_XXX +/* + * Since several people happen to have problems with their drives, + * it might be a good idea to allow a config file override for the + * floppy seek settle time; the value is in 1s / FDSEEKWAIT; + * Preferrable values are powers of two, since the compiler can + * replace the divide operations by simple shifts then! + */ +#ifndef FDSEEKWAIT +# define FDSEEKWAIT 16 /* has been 32 in FreeBSD 1.1.5.1 */ +#endif + /* * this biotab field doubles as a field for the physical unit number * on the controller @@ -323,17 +268,87 @@ int fd_debug = 0; struct isa_device *fdcdevs[NFDC]; + +/* + * Templates for the kern_devconf structures used when we attach. + */ +static struct kern_devconf kdc_fd[NFD] = { { + 0, 0, 0, /* filled in by kern_devconf.c */ + "fd", 0, { MDDT_DISK, 0 }, + fd_externalize, 0, fd_goaway, DISK_EXTERNALLEN, + 0, /* parent */ + 0, /* parentdata */ + DC_UNKNOWN, /* state */ + "floppy disk" +} }; + +struct kern_devconf kdc_fdc[NFDC] = { { + 0, 0, 0, /* filled in by kern_devconf.c */ + "fdc", 0, { MDDT_ISA, 0, "bio" }, + isa_generic_externalize, 0, fdc_goaway, ISA_EXTERNALLEN, + 0, /* parent */ + 0, /* parentdata */ + DC_UNKNOWN, /* state */ + "floppy disk/tape controller" +} }; + +static inline void +fd_registerdev(int ctlr, int unit) +{ + if(unit != 0) + kdc_fd[unit] = kdc_fd[0]; + + kdc_fd[unit].kdc_unit = unit; + kdc_fd[unit].kdc_parent = &kdc_fdc[ctlr]; + kdc_fd[unit].kdc_parentdata = 0; + dev_attach(&kdc_fd[unit]); +} + +static inline void +fdc_registerdev(struct isa_device *dvp) +{ + int unit = dvp->id_unit; + + if(unit != 0) + kdc_fdc[unit] = kdc_fdc[0]; + + kdc_fdc[unit].kdc_unit = unit; + kdc_fdc[unit].kdc_parent = &kdc_isa0; + kdc_fdc[unit].kdc_parentdata = dvp; + dev_attach(&kdc_fdc[unit]); +} + +static int +fdc_goaway(struct kern_devconf *kdc, int force) +{ + if(force) { + dev_detach(kdc); + return 0; + } else { + return EBUSY; /* XXX fix */ + } +} + +static int +fd_goaway(struct kern_devconf *kdc, int force) +{ + dev_detach(kdc); + return 0; +} + /* * Provide hw.devconf information. */ static int -fd_externalize(struct proc *p, struct kern_devconf *kdc, void *userp, size_t len) +fd_externalize(struct proc *p, struct kern_devconf *kdc, void *userp, + size_t len) { return disk_externalize(fd_data[kdc->kdc_unit].fdsu, userp, &len); } static int -fdc_externalize(struct proc *p, struct kern_devconf *kdc, void *userp, size_t len) +fdc_externalize(struct proc *p, struct kern_devconf *kdc, void *userp, + size_t len) { return isa_externalize(fdcdevs[kdc->kdc_unit], userp, &len); } @@ -529,10 +544,30 @@ fdsize(dev) return(0); } + /****************************************************************************/ /* motor control stuff */ -/* remember to not deselect the drive we're working on */ /****************************************************************************/ + +static void +fdc_gotobed(void *arg1) +{ + int fdcu = (int)arg1; + int fdout = fdc_data[fdcu].fdout; + + if((fdout & FDO_FRST) == 0) + /* huh? */ + return; + + /* reset controller */ + fdout &= ~ (FDO_FRST|FDO_FDMAEN); + + outb(fdc_data[fdcu].baseport+FDOUT, fdout); + fdc_data[fdcu].fdout = fdout; + TRACE1("[0x%x->FDOUT]", fdout); +} + + static void set_motor(fdcu, fdsu, turnon) fdcu_t fdcu; @@ -541,22 +576,31 @@ set_motor(fdcu, fdsu, turnon) { int fdout = fdc_data[fdcu].fdout; int needspecify = 0; + int x; + /* if a timeout is almost due, avoid killing the FDC */ + x = splsoftclock(); if(turnon) { + if((fdout & (FDO_FRST|FDO_FDMAEN))) + untimeout(fdc_gotobed, (void *)fdcu); fdout &= ~FDO_FDSEL; fdout |= (FDO_MOEN0 << fdsu) + fdsu; } else fdout &= ~(FDO_MOEN0 << fdsu); + splx(x); - if(!turnon - && (fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0) - /* gonna turn off the last drive, put FDC to bed */ - fdout &= ~ (FDO_FRST|FDO_FDMAEN); - else { + if(turnon) { /* make sure controller is selected and specified */ if((fdout & (FDO_FRST|FDO_FDMAEN)) == 0) needspecify = 1; fdout |= (FDO_FRST|FDO_FDMAEN); + } else { + if((fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0) + /* + * gonna turn off the last drive, schedule a timeout + * to put the FDC to bed later (just for sanity) + */ + timeout(fdc_gotobed, (void *)fdcu, hz * 60); } outb(fdc_data[fdcu].baseport+FDOUT, fdout); @@ -572,10 +616,10 @@ set_motor(fdcu, fdsu, turnon) out_fdc(fdcu, NE7CMD_SPECIFY); out_fdc(fdcu, NE7_SPEC_1(3, 240)); out_fdc(fdcu, NE7_SPEC_2(2, 0)); + fdc_data[fdcu].state = STARTRECAL; /* need to recalib now */ } } -/* ARGSUSED */ static void fd_turnoff(void *arg1) { @@ -589,7 +633,6 @@ fd_turnoff(void *arg1) splx(s); } -/* ARGSUSED */ static void fd_motor_on(void *arg1) { @@ -615,7 +658,7 @@ fd_turnon(fdu) { fd->flags |= (FD_MOTOR + FD_MOTOR_WAIT); set_motor(fd->fdc->fdcu, fd->fdsu, TURNON); - timeout(fd_motor_on, (caddr_t)fdu, hz); /* in 1 sec its ok */ + timeout(fd_motor_on, (void *)fdu, hz); /* in 1 sec its ok */ } } @@ -857,7 +900,7 @@ fdstrategy(struct buf *bp) dp = &(fdc->head); s = splbio(); disksort(dp, bp); - untimeout(fd_turnoff, (caddr_t)fdu); /* a good idea */ + untimeout(fd_turnoff, (void *)fdu); /* a good idea */ fdstart(fdcu); splx(s); return; @@ -889,7 +932,6 @@ fdstart(fdcu) splx(s); } -/* ARGSUSED */ static void fd_timeout(void *arg1) { @@ -941,7 +983,6 @@ fd_timeout(void *arg1) } /* just ensure it has the right spl */ -/* ARGSUSED */ static void fd_pseudointr(void *arg1) { @@ -1023,8 +1064,8 @@ fdstate(fdcu, fdc) TRACE1("fd%d", fdu); TRACE1("[%s]", fdstates[fdc->state]); TRACE1("(0x%x)", fd->flags); - untimeout(fd_turnoff, (caddr_t)fdu); - timeout(fd_turnoff, (caddr_t)fdu, 4 * hz); + untimeout(fd_turnoff, (void *)fdu); + timeout(fd_turnoff, (void *)fdu, 4 * hz); switch (fdc->state) { case DEVIDLE: @@ -1055,9 +1096,9 @@ fdstate(fdcu, fdc) } else /* at least make sure we are selected */ { + fdc->state = DOSEEK; set_motor(fdcu, fd->fdsu, TURNON); } - fdc->state = DOSEEK; break; case DOSEEK: if (bp->b_cylin == fd->track) @@ -1081,7 +1122,7 @@ fdstate(fdcu, fdc) return(0); /* will return later */ case SEEKWAIT: /* allow heads to settle */ - timeout(fd_pseudointr, (caddr_t)fdcu, hz / 32); + timeout(fd_pseudointr, (void *)fdcu, hz / FDSEEKWAIT); fdc->state = SEEKCOMPLETE; return(0); /* will return later */ case SEEKCOMPLETE : /* SEEK DONE, START DMA */ @@ -1121,7 +1162,7 @@ fdstate(fdcu, fdc) { printf( "fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n", - fdu, descyl, cyl, st0, NE7_ST0BITS); + fdu, descyl, cyl, st0); return(retrier(fdcu)); } } @@ -1207,10 +1248,10 @@ fdstate(fdcu, fdc) out_fdc(fdcu, fd->ft->datalen); /* data length */ } fdc->state = IOCOMPLETE; - timeout(fd_timeout, (caddr_t)fdcu, hz); + timeout(fd_timeout, (void *)fdcu, hz); return(0); /* will return later */ case IOCOMPLETE: /* IO DONE, post-analyze */ - untimeout(fd_timeout, (caddr_t)fdcu); + untimeout(fd_timeout, (void *)fdcu); for(i=0;i<7;i++) { fdc->status[i] = in_fdc(fdcu); @@ -1283,7 +1324,7 @@ fdstate(fdcu, fdc) return(0); /* will return later */ case RECALWAIT: /* allow heads to settle */ - timeout(fd_pseudointr, (caddr_t)fdcu, hz / 32); + timeout(fd_pseudointr, (void *)fdcu, hz / FDSEEKWAIT); fdc->state = RECALCOMPLETE; return(0); /* will return later */ case RECALCOMPLETE: @@ -1322,12 +1363,7 @@ fdstate(fdcu, fdc) { return(0); /* time's not up yet */ } - /* - * since the controller was off, it has lost its - * idea about the current track it were; thus, - * recalibrate the bastard - */ - fdc->state = STARTRECAL; + fdc->state = DOSEEK; return(1); /* will return immediatly */ default: printf("Unexpected FD int->"); @@ -1452,7 +1488,7 @@ fdformat(dev, finfo, p) + finfo->head * fd->ft->sectrac) * fdblk / DEV_BSIZE; bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; - bp->b_un.b_addr = (caddr_t)finfo; + bp->b_un.b_addr = (void *)finfo; /* now do the format */ fdstrategy(bp); @@ -1461,7 +1497,7 @@ fdformat(dev, finfo, p) s = splbio(); while(!(bp->b_flags & B_DONE)) { - rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz); + rv = tsleep((void *)bp, PRIBIO, "fdform", 20 * hz); if(rv == EWOULDBLOCK) break; } @@ -1586,6 +1622,15 @@ fdioctl(dev, cmd, addr, flag, p) fd_data[FDUNIT(minor(dev))].options = *(int *)addr; break; +#ifdef DEBUG + case FD_DEBUG: + /* this is considered harmful; only allow for superuser */ + if(suser(p->p_ucred, &p->p_acflag) != 0) + return EPERM; + fd_debug = *(int *)addr; + break; +#endif + default: error = ENOTTY; break;