1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-16 10:20:30 +00:00

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.
This commit is contained in:
Joerg Wunsch 1994-10-30 20:04:40 +00:00
parent a6a21d9edf
commit 5d04c702eb
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=4011
3 changed files with 432 additions and 297 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;