summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2004-09-22 22:13:00 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2004-09-22 22:13:00 +0000
commitf3ecf07ff4fd224ca32417039ccb99d8532ec9ac (patch)
treeb6f8aece36832624c9052889bfe5795b335a3b5d
parentea075872881abbf59bd05df6aa7635696fe3e426 (diff)
Bring some enhancements and fixes to fdc(4) from NetBSD:
- better state machine, will prevent "eject fd0" with an empty drive to spin. - will not attach fd children to fdc if no floppy drive is present (though the PROM usually finds this for us). - use biowait() in fdformat() instead of rolling our own. - drop 5"1/4 formats table. - cope with non 512 bytes per sector formats.
-rw-r--r--sys/arch/sparc/dev/fd.c657
-rw-r--r--sys/arch/sparc/dev/fdreg.h3
-rw-r--r--sys/arch/sparc/dev/fdvar.h25
-rw-r--r--sys/arch/sparc/sparc/bsd_fdintr.s33
-rw-r--r--sys/arch/sparc/sparc/genassym.cf5
5 files changed, 448 insertions, 275 deletions
diff --git a/sys/arch/sparc/dev/fd.c b/sys/arch/sparc/dev/fd.c
index 9df2ebfb3e2..abd328067d8 100644
--- a/sys/arch/sparc/dev/fd.c
+++ b/sys/arch/sparc/dev/fd.c
@@ -1,7 +1,42 @@
-/* $OpenBSD: fd.c,v 1.36 2004/04/02 04:31:21 deraadt Exp $ */
+/* $OpenBSD: fd.c,v 1.37 2004/09/22 22:12:57 miod Exp $ */
/* $NetBSD: fd.c,v 1.51 1997/05/24 20:16:19 pk Exp $ */
/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Paul Kranenburg.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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.
+ */
+/*-
* Copyright (c) 1993, 1994, 1995 Charles Hannum.
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
@@ -84,28 +119,29 @@
#define b_cylin b_resid
-#define FD_DEBUG
#ifdef FD_DEBUG
int fdc_debug = 0;
#endif
enum fdc_state {
DEVIDLE = 0,
- MOTORWAIT,
- DOSEEK,
- SEEKWAIT,
- SEEKTIMEDOUT,
- SEEKCOMPLETE,
- DOIO,
- IOCOMPLETE,
- IOTIMEDOUT,
- DORESET,
- RESETCOMPLETE,
- RESETTIMEDOUT,
- DORECAL,
- RECALWAIT,
- RECALTIMEDOUT,
- RECALCOMPLETE,
+ MOTORWAIT, /* 1 */
+ DOSEEK, /* 2 */
+ SEEKWAIT, /* 3 */
+ SEEKTIMEDOUT, /* 4 */
+ SEEKCOMPLETE, /* 5 */
+ DOIO, /* 6 */
+ IOCOMPLETE, /* 7 */
+ IOTIMEDOUT, /* 8 */
+ IOCLEANUPWAIT, /* 9 */
+ IOCLEANUPTIMEDOUT,/*10 */
+ DORESET, /* 11 */
+ RESETCOMPLETE, /* 12 */
+ RESETTIMEDOUT, /* 13 */
+ DORECAL, /* 14 */
+ RECALWAIT, /* 15 */
+ RECALTIMEDOUT, /* 16 */
+ RECALCOMPLETE, /* 17 */
};
/* software state, per controller */
@@ -121,6 +157,7 @@ struct fdc_softc {
#define FDC_82077 0x01
#define FDC_NEEDHEADSETTLE 0x02
#define FDC_EIS 0x04
+#define FDC_NEEDMOTORWAIT 0x08
int sc_errors; /* number of retries so far */
int sc_overruns; /* number of DMA overruns */
int sc_cfg; /* current configuration */
@@ -129,7 +166,8 @@ struct fdc_softc {
#define sc_reg_fifo sc_io.fdcio_reg_fifo
#define sc_reg_dor sc_io.fdcio_reg_dor
#define sc_reg_drs sc_io.fdcio_reg_msr
-#define sc_istate sc_io.fdcio_istate
+#define sc_itask sc_io.fdcio_itask
+#define sc_istatus sc_io.fdcio_istatus
#define sc_data sc_io.fdcio_data
#define sc_tc sc_io.fdcio_tc
#define sc_nstat sc_io.fdcio_nstat
@@ -159,13 +197,10 @@ __inline struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t);
/* The order of entries in the following table is important -- BEWARE! */
struct fd_type fd_types[] = {
- { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS, "1.44MB" }, /* 1.44MB diskette */
- { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB" }, /* 1.2 MB AT-diskettes */
- { 9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */
- { 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
+ { 18,2,36,2,0xff,0xcf,0x1b,0x54,80,2880,1,FDC_500KBPS, "1.44MB" }, /* 1.44MB diskette */
{ 9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB" }, /* 3.5" 720kB diskette */
- { 9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x" }, /* 720kB in 1.2MB drive */
{ 9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x" }, /* 360kB in 720kB drive */
+ { 8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, "1.2MB/NEC" } /* 1.2 MB japanese format */
};
/* software state, per disk (with up to 4 disks per ctlr) */
@@ -225,14 +260,14 @@ void fd_set_motor(struct fdc_softc *fdc);
void fd_motor_off(void *arg);
void fd_motor_on(void *arg);
int fdcresult(struct fdc_softc *fdc);
-int out_fdc(struct fdc_softc *fdc, u_char x);
+int fdc_wrfifo(struct fdc_softc *fdc, u_char x);
void fdcstart(struct fdc_softc *fdc);
-void fdcstatus(struct device *dv, int n, char *s);
+void fdcstatus(struct fdc_softc *fdc, char *s);
void fdc_reset(struct fdc_softc *fdc);
void fdctimeout(void *arg);
void fdcpseudointr(void *arg);
#ifdef FDC_C_HANDLER
-int fdchwintr(struct fdc_softc *);
+int fdc_c_hwintr(struct fdc_softc *);
#else
void fdchwintr(void);
#endif
@@ -243,7 +278,7 @@ void fdfinish(struct fd_softc *fd, struct buf *bp);
int fdformat(dev_t, struct fd_formb *, struct proc *);
void fd_do_eject(struct fd_softc *);
void fd_mountroot_hook(struct device *);
-static void fdconf(struct fdc_softc *);
+static int fdconf(struct fdc_softc *);
#if IPL_FDSOFT == 4
#define IE_FDSOFT IE_L4
@@ -332,14 +367,18 @@ fdprint(aux, fdc)
return (QUIET);
}
-static void
+/*
+ * Configure several parameters and features on the FDC.
+ * Return 0 on success.
+ */
+static int
fdconf(fdc)
struct fdc_softc *fdc;
{
int vroom;
- if (out_fdc(fdc, NE7CMD_DUMPREG) || fdcresult(fdc) != 10)
- return;
+ if (fdc_wrfifo(fdc, NE7CMD_DUMPREG) || fdcresult(fdc) != 10)
+ return (-1);
/*
* dumpreg[7] seems to be a motor-off timeout; set it to whatever
@@ -349,11 +388,35 @@ fdconf(fdc)
vroom = 0x64;
/* Configure controller to use FIFO and Implied Seek */
- out_fdc(fdc, NE7CMD_CFG);
- out_fdc(fdc, vroom);
- out_fdc(fdc, fdc->sc_cfg);
- out_fdc(fdc, 0); /* PRETRK */
- /* No result phase */
+ if (fdc_wrfifo(fdc, NE7CMD_CFG) != 0)
+ return (-1);
+ if (fdc_wrfifo(fdc, vroom) != 0)
+ return (-1);
+ if (fdc_wrfifo(fdc, fdc->sc_cfg) != 0)
+ return (-1);
+ if (fdc_wrfifo(fdc, 0) != 0) /* PRETRK */
+ return (-1);
+ /* No result phase for the NE7CMD_CFG command */
+
+ if ((fdc->sc_flags & FDC_82077) != 0) {
+ /* Lock configuration accross soft resets. */
+ if (fdc_wrfifo(fdc, NE7CMD_LOCK | CFG_LOCK) != 0 ||
+ fdcresult(fdc) != 1) {
+#ifdef FD_DEBUG
+ printf("fdconf: CFGLOCK failed");
+#endif
+ return (-1);
+ }
+ }
+ return (0);
+#if 0
+ if (fdc_wrfifo(fdc, NE7CMD_VERSION) == 0 &&
+ fdcresult(fdc) == 1 && fdc->sc_status[0] == 0x90) {
+ if (fdc_debug)
+ printf("[version cmd]");
+ }
+#endif
+
}
void
@@ -375,13 +438,14 @@ fdcattach(parent, self, aux)
ca->ca_ra.ra_len);
fdc->sc_state = DEVIDLE;
- fdc->sc_istate = ISTATE_IDLE;
+ fdc->sc_itask = FDC_ITASK_NONE;
+ fdc->sc_istatus = FDC_ISTATUS_NONE;
fdc->sc_flags |= FDC_EIS;
TAILQ_INIT(&fdc->sc_drives);
pri = ca->ca_ra.ra_intr[0].int_pri;
#ifdef FDC_C_HANDLER
- fdc->sc_hih.ih_fun = (void *)fdchwintr;
+ fdc->sc_hih.ih_fun = (void *)fdc_c_hwintr;
fdc->sc_hih.ih_arg = fdc;
intr_establish(pri, &fdc->sc_hih, IPL_FD);
#else
@@ -411,30 +475,26 @@ fdcattach(parent, self, aux)
}
if (code == '7') {
fdc->sc_flags |= FDC_82077;
+ fdc->sc_flags |= FDC_NEEDMOTORWAIT;
} else {
fdc->sc_reg_msr = &((struct fdreg_72 *)fdc->sc_reg)->fd_msr;
fdc->sc_reg_fifo = &((struct fdreg_72 *)fdc->sc_reg)->fd_fifo;
fdc->sc_reg_dor = 0;
}
-#ifdef FD_DEBUG
- if (out_fdc(fdc, NE7CMD_VERSION) == 0 &&
- fdcresult(fdc) == 1 && fdc->sc_status[0] == 0x90) {
- if (fdc_debug)
- printf("[version cmd]");
- }
-#endif
-
/*
* Configure controller; enable FIFO, Implied seek, no POLL mode?.
* Note: CFG_EFIFO is active-low, initial threshold value: 8
*/
fdc->sc_cfg = CFG_EIS|/*CFG_EFIFO|*/CFG_POLL|(8 & CFG_THRHLD_MASK);
- fdconf(fdc);
+ if (fdconf(fdc) != 0) {
+ printf("%s: no drives attached\n", fdc->sc_dev.dv_xname);
+ return;
+ }
- if (fdc->sc_flags & FDC_82077) {
+ if ((fdc->sc_flags & FDC_82077) != 0) {
/* Lock configuration across soft resets. */
- out_fdc(fdc, NE7CMD_LOCK | CFG_LOCK);
+ fdc_wrfifo(fdc, NE7CMD_LOCK | CFG_LOCK);
if (fdcresult(fdc) != 1)
printf(" CFGLOCK: unexpected response");
}
@@ -516,25 +576,26 @@ fdmatch(parent, match, aux)
/* XXX - for now, punt on more than one drive */
return (0);
- if (fdc->sc_flags & FDC_82077) {
+ if ((fdc->sc_flags & FDC_82077) != 0) {
/* select drive and turn on motor */
*fdc->sc_reg_dor = drive | FDO_FRST | FDO_MOEN(drive);
+ /* wait for motor to spin up */
+ delay(250000);
} else {
auxregbisc(AUXIO4C_FDS, 0);
}
- /* wait for motor to spin up */
- delay(250000);
fdc->sc_nstat = 0;
- out_fdc(fdc, NE7CMD_RECAL);
- out_fdc(fdc, drive);
+ fdc_wrfifo(fdc, NE7CMD_RECAL);
+ fdc_wrfifo(fdc, drive);
+
/* wait for recalibrate */
for (n = 0; n < 10000; n++) {
delay(1000);
if ((*fdc->sc_reg_msr & (NE7_RQM|NE7_DIO|NE7_CB)) == NE7_RQM) {
/* wait a bit longer till device *really* is ready */
delay(100000);
- if (out_fdc(fdc, NE7CMD_SENSEI))
+ if (fdc_wrfifo(fdc, NE7CMD_SENSEI))
break;
if (fdcresult(fdc) == 1 && fdc->sc_status[0] == 0x80)
/*
@@ -552,14 +613,14 @@ fdmatch(parent, match, aux)
int i;
printf("fdprobe: %d stati:", n);
for (i = 0; i < n; i++)
- printf(" %x", fdc->sc_status[i]);
+ printf(" 0x%x", fdc->sc_status[i]);
printf("\n");
}
#endif
ok = (n == 2 && (fdc->sc_status[0] & 0xf8) == 0x20) ? 1 : 0;
/* turn off motor */
- if (fdc->sc_flags & FDC_82077) {
+ if ((fdc->sc_flags & FDC_82077) != 0) {
/* deselect drive and turn motor off */
*fdc->sc_reg_dor = FDO_FRST | FDO_DS;
} else {
@@ -583,6 +644,10 @@ fdattach(parent, self, aux)
struct fd_type *type = fa->fa_deftype;
int drive = fa->fa_drive;
+ /* Setup timeouts */
+ timeout_set(&fd->fd_motor_on_to, fd_motor_on, fd);
+ timeout_set(&fd->fd_motor_off_to, fd_motor_off, fd);
+
/* XXX Allow `flags' to override device type? */
if (type)
@@ -596,9 +661,10 @@ fdattach(parent, self, aux)
fd->sc_deftype = type;
fdc->sc_fd[drive] = fd;
- out_fdc(fdc, NE7CMD_SPECIFY);
- out_fdc(fdc, type->steprate);
- out_fdc(fdc, 6 | NE7_SPECIFY_NODMA);
+ fdc_wrfifo(fdc, NE7CMD_SPECIFY);
+ fdc_wrfifo(fdc, type->steprate);
+ /* XXX head load time == 6ms */
+ fdc_wrfifo(fdc, 6 | NE7_SPECIFY_NODMA);
/*
* Initialize and attach the disk structure.
@@ -624,10 +690,6 @@ fdattach(parent, self, aux)
/* XXX Need to do some more fiddling with sc_dk. */
dk_establish(&fd->sc_dk, &fd->sc_dv);
-
- /* Setup timeouts */
- timeout_set(&fd->fd_motor_on_to, fd_motor_on, fd);
- timeout_set(&fd->fd_motor_off_to, fd_motor_off, fd);
}
__inline struct fd_type *
@@ -655,7 +717,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 % FD_BSIZE(fd)) != 0 ||
+ (bp->b_blkno * DEV_BSIZE) % FD_BSIZE(fd) != 0) &&
(bp->b_flags & B_FORMAT) == 0)) {
bp->b_error = EINVAL;
goto bad;
@@ -665,10 +728,11 @@ fdstrategy(bp)
if (bp->b_bcount == 0)
goto done;
- sz = howmany(bp->b_bcount, FDC_BSIZE);
+ sz = howmany(bp->b_bcount, DEV_BSIZE);
- if (bp->b_blkno + sz > fd->sc_type->size) {
- sz = fd->sc_type->size - bp->b_blkno;
+ if (bp->b_blkno + sz > (fd->sc_type->size * DEV_BSIZE) / FD_BSIZE(fd)) {
+ sz = (fd->sc_type->size * DEV_BSIZE) / FD_BSIZE(fd)
+ - bp->b_blkno;
if (sz == 0) {
/* If exactly at end of disk, return EOF. */
bp->b_resid = bp->b_bcount;
@@ -683,7 +747,8 @@ fdstrategy(bp)
bp->b_bcount = sz << DEV_BSHIFT;
}
- bp->b_cylin = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl;
+ bp->b_cylin = (bp->b_blkno * DEV_BSIZE) /
+ (FD_BSIZE(fd) * fd->sc_type->seccyl);
#ifdef FD_DEBUG
if (fdc_debug > 1)
@@ -804,16 +869,14 @@ fd_set_motor(fdc)
status |= FDO_MOEN(n);
*fdc->sc_reg_dor = status;
} else {
- int on = 0;
-
- for (n = 0; n < 4; n++)
- if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
- on = 1;
- if (on) {
- auxregbisc(AUXIO4C_FDS, 0);
- } else {
- auxregbisc(0, AUXIO4C_FDS);
+ for (n = 0; n < 4; n++) {
+ if ((fd = fdc->sc_fd[n]) != NULL &&
+ (fd->sc_flags & FD_MOTOR) != 0) {
+ auxregbisc(AUXIO4C_FDS, 0);
+ return;
+ }
}
+ auxregbisc(0, AUXIO4C_FDS);
}
}
@@ -845,15 +908,19 @@ fd_motor_on(arg)
splx(s);
}
+/*
+ * Get status bytes off the FDC after a command has finished
+ * Returns the number of status bytes read; -1 on error.
+ * The return value is also stored in `sc_nstat'.
+ */
int
fdcresult(fdc)
struct fdc_softc *fdc;
{
u_char i;
- int j = 100000,
- n = 0;
+ int j, n = 0;
- for (; j; j--) {
+ for (j = 100000; j; j--) {
i = *fdc->sc_reg_msr & (NE7_DIO | NE7_RQM | NE7_CB);
if (i == NE7_RQM)
return (fdc->sc_nstat = n);
@@ -864,26 +931,33 @@ fdcresult(fdc)
}
fdc->sc_status[n++] = *fdc->sc_reg_fifo;
} else
- delay(10);
+ delay(1);
}
+
log(LOG_ERR, "fdcresult: timeout\n");
return (fdc->sc_nstat = -1);
}
+/*
+ * Write a command byte to the FDC.
+ * Returns 0 on success; -1 on failure (i.e. timeout)
+ */
int
-out_fdc(fdc, x)
+fdc_wrfifo(fdc, x)
struct fdc_softc *fdc;
u_char x;
{
- int i = 100000;
+ int i;
- while (((*fdc->sc_reg_msr & (NE7_DIO|NE7_RQM)) != NE7_RQM) && i-- > 0)
+ for (i = 100000; i-- > 0;) {
+ if ((*fdc->sc_reg_msr & (NE7_DIO|NE7_RQM)) == NE7_RQM) {
+ /* The chip is ready */
+ *fdc->sc_reg_fifo = x;
+ return (0);
+ }
delay(1);
- if (i <= 0)
- return (-1);
-
- *fdc->sc_reg_fifo = x;
- return (0);
+ }
+ return (-1);
}
int
@@ -900,7 +974,7 @@ fdopen(dev, flags, fmt, p)
if (unit >= fd_cd.cd_ndevs)
return (ENXIO);
fd = fd_cd.cd_devs[unit];
- if (fd == 0)
+ if (fd == NULL)
return (ENXIO);
type = fd_dev_to_type(fd, dev);
if (type == NULL)
@@ -1001,29 +1075,30 @@ fdcstart(fdc)
}
void
-fdcstatus(dv, n, s)
- struct device *dv;
- int n;
+fdcstatus(fdc, s)
+ struct fdc_softc *fdc;
char *s;
{
- struct fdc_softc *fdc = (void *)dv->dv_parent;
+ struct fd_softc *fd = fdc->sc_drives.tqh_first;
+ int n;
+
+ /* Just print last status */
+ n = fdc->sc_nstat;
#if 0
/*
* A 82072 seems to return <invalid command> on
* gratuitous Sense Interrupt commands.
*/
- if (n == 0 && (fdc->sc_flags & FDC_82077)) {
- out_fdc(fdc, NE7CMD_SENSEI);
+ if (n == 0 && (fdc->sc_flags & FDC_82077) != 0) {
+ fdc_wrfifo(fdc, NE7CMD_SENSEI);
(void) fdcresult(fdc);
n = 2;
}
#endif
- /* Just print last status */
- n = fdc->sc_nstat;
-
- printf("%s: %s: state %d", dv->dv_xname, s, fdc->sc_state);
+ printf("%s: %s: state %d",
+ fd ? fd->sc_dv.dv_xname : "fdc", s, fdc->sc_state);
switch (n) {
case 0:
@@ -1054,11 +1129,17 @@ fdctimeout(arg)
void *arg;
{
struct fdc_softc *fdc = arg;
- struct fd_softc *fd = fdc->sc_drives.tqh_first;
+ struct fd_softc *fd;
int s;
s = splbio();
- fdcstatus(&fd->sc_dv, 0, "timeout");
+ fd = fdc->sc_drives.tqh_first;
+ if (fd == NULL) {
+ printf("%s: timeout but no I/O pending: statu %d, istatus=%d\n",
+ fdc->sc_dev.dv_xname, fdc->sc_state, fdc->sc_istatus);
+ fdc->sc_state = DEVIDLE;
+ goto out;
+ }
if (fd->sc_q.b_actf)
fdc->sc_state++;
@@ -1066,6 +1147,7 @@ fdctimeout(arg)
fdc->sc_state = DEVIDLE;
(void) fdcstate(fdc);
+out:
splx(s);
}
@@ -1089,55 +1171,67 @@ fdcpseudointr(arg)
* (in-window) handler.
*/
int
-fdchwintr(fdc)
+fdc_c_hwintr(fdc)
struct fdc_softc *fdc;
{
- switch (fdc->sc_istate) {
- case ISTATE_IDLE:
+ switch (fdc->sc_itask) {
+ case FDC_ITASK_NONE:
return (0);
- case ISTATE_SENSEI:
- out_fdc(fdc, NE7CMD_SENSEI);
- fdcresult(fdc);
- fdc->sc_istate = ISTATE_IDLE;
+ case FDC_ITASK_SENSEI:
+ if (fdc_wrfifo(fdc, NE7CMD_SENSEI) != 0 || fdcresult(fdc) == -1)
+ fdc->sc_istatus = FDC_ISTATUS_ERROR;
+ else
+ fdc->sc_istatus = FDC_ISTATUS_DONE;
FD_SET_SWINTR;
goto done;
- case ISTATE_SPURIOUS:
- fdcresult(fdc);
- fdc->sc_istate = ISTATE_SPURIOUS;
- printf("fdc: stray hard interrupt... ");
+ case FDC_ITASK_RESULT:
+ if (fdcresult(fdc) == -1)
+ fdc->sc_istatus = FDC_ISTATUS_ERROR;
+ else
+ fdc->sc_istatus = FDC_ISTATUS_DONE;
FD_SET_SWINTR;
goto done;
- case ISTATE_DMA:
+ case FDC_ITASK_DMA:
+ /* Proceed with pseudo-DMA below */
break;
default:
- printf("fdc: goofed ...\n");
+ printf("fdc: stray hard interrupt: itask=%d\n", fdc->sc_itask);
+ fdc->sc_istatus = FDC_ISTATUS_SPURIOUS;
+ FD_SET_SWINTR;
goto done;
}
+ /*
+ * Pseudo DMA in progress
+ */
for (;;) {
register int msr;
msr = *fdc->sc_reg_msr;
if ((msr & NE7_RQM) == 0)
+ /* That's all this round */
break;
if ((msr & NE7_NDM) == 0) {
fdcresult(fdc);
- fdc->sc_istate = ISTATE_IDLE;
+ fdc->sc_istatus = FDC_ISTATUS_DONE;
FD_SET_SWINTR;
- printf("fdc: overrun: tc = %d\n", fdc->sc_tc);
+#ifdef FD_DEBUG
+ if (fdc_debug > 1)
+ printf("fdc: overrun: tc = %d\n", fdc->sc_tc);
+#endif
break;
}
- if (msr & NE7_DIO) {
+ /* Another byte can be transferred */
+ if ((msr & NE7_DIO) != 0)
*fdc->sc_data++ = *fdc->sc_reg_fifo;
- } else {
+ else
*fdc->sc_reg_fifo = *fdc->sc_data++;
- }
if (--fdc->sc_tc == 0) {
- fdc->sc_istate = ISTATE_DONE;
+ fdc->sc_istatus = FDC_ISTATUS_DONE;
FTC_FLIP;
fdcresult(fdc);
FD_SET_SWINTR;
@@ -1156,10 +1250,19 @@ fdcswintr(fdc)
{
int s;
- if (fdc->sc_istate != ISTATE_DONE)
+ if (fdc->sc_istatus == FDC_ISTATUS_NONE)
+ /* This (software) interrupt is not for us */
return (0);
- fdc->sc_istate = ISTATE_IDLE;
+ switch (fdc->sc_istatus) {
+ case FDC_ISTATUS_ERROR:
+ printf("fdc: ierror status: state %d\n", fdc->sc_state);
+ break;
+ case FDC_ISTATUS_SPURIOUS:
+ printf("fdc: spurious interrupt: state %d\n", fdc->sc_state);
+ break;
+ }
+
s = splbio();
fdcstate(fdc);
splx(s);
@@ -1173,8 +1276,12 @@ fdcstate(fdc)
#define st0 fdc->sc_status[0]
#define st1 fdc->sc_status[1]
#define cyl fdc->sc_status[1]
-#define OUT_FDC(fdc, c, s) \
- do { if (out_fdc(fdc, (c))) { (fdc)->sc_state = (s); goto loop; } } while(0)
+#define FDC_WRFIFO(fdc, c) \
+ do { \
+ if (fdc_wrfifo(fdc, (c))) { \
+ goto xxx; \
+ } \
+ } while (0)
struct fd_softc *fd;
struct buf *bp;
@@ -1183,18 +1290,18 @@ fdcstate(fdc)
struct fd_formb *finfo = NULL;
- if (fdc->sc_istate != ISTATE_IDLE) {
- /* Trouble... */
- printf("fdc: spurious interrupt: state %d, istate=%d\n",
- fdc->sc_state, fdc->sc_istate);
- fdc->sc_istate = ISTATE_IDLE;
- if (fdc->sc_state == RESETCOMPLETE ||
- fdc->sc_state == RESETTIMEDOUT) {
- panic("fdcintr: spurious interrupt can't be cleared");
- }
- goto doreset;
+ if (fdc->sc_istatus == FDC_ISTATUS_ERROR) {
+ /* Prevent loop if the reset sequence produces errors */
+ if (fdc->sc_state != RESETCOMPLETE &&
+ fdc->sc_state != RECALWAIT &&
+ fdc->sc_state != RECALCOMPLETE)
+ fdc->sc_state = DORESET;
}
+ /* Clear I task/status field */
+ fdc->sc_istatus = FDC_ISTATUS_NONE;
+ fdc->sc_itask = FDC_ITASK_NONE;
+
loop:
/* Is there a drive for the controller to do a transfer with? */
fd = fdc->sc_drives.tqh_first;
@@ -1220,7 +1327,7 @@ loop:
fdc->sc_errors = 0;
fd->sc_skip = 0;
fd->sc_bcount = bp->b_bcount;
- fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
+ fd->sc_blkno = (bp->b_blkno * DEV_BSIZE) / FD_BSIZE(fd);
timeout_del(&fd->fd_motor_off_to);
if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
fdc->sc_state = MOTORWAIT;
@@ -1236,7 +1343,7 @@ loop:
fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
fd_set_motor(fdc);
fdc->sc_state = MOTORWAIT;
- if (fdc->sc_flags & FDC_82077) { /* XXX */
+ if ((fdc->sc_flags & FDC_NEEDMOTORWAIT) != 0) { /* XXX */
/* Allow .25s for motor to stabilize. */
timeout_add(&fd->fd_motor_on_to, hz / 4);
} else {
@@ -1261,26 +1368,27 @@ loop:
if (fd->sc_cylin == bp->b_cylin)
goto doio;
- /* specify command */
- OUT_FDC(fdc, NE7CMD_SPECIFY, SEEKTIMEDOUT);
- OUT_FDC(fdc, fd->sc_type->steprate, SEEKTIMEDOUT);
- /* XXX head load time == 6ms */
- OUT_FDC(fdc, 6 | NE7_SPECIFY_NODMA, SEEKTIMEDOUT);
-
- fdc->sc_istate = ISTATE_SENSEI;
- /* seek function */
- OUT_FDC(fdc, NE7CMD_SEEK, SEEKTIMEDOUT);
- OUT_FDC(fdc, fd->sc_drive, SEEKTIMEDOUT); /* drive number */
- OUT_FDC(fdc, bp->b_cylin * fd->sc_type->step, SEEKTIMEDOUT);
-
fd->sc_cylin = -1;
fdc->sc_state = SEEKWAIT;
fdc->sc_nstat = 0;
fd->sc_dk.dk_seek++;
- disk_busy(&fd->sc_dk);
+ disk_busy(&fd->sc_dk);
timeout_add(&fdc->fdctimeout_to, 4 * hz);
+
+ /* specify command */
+ FDC_WRFIFO(fdc, NE7CMD_SPECIFY);
+ FDC_WRFIFO(fdc, fd->sc_type->steprate);
+ /* XXX head load time == 6ms */
+ FDC_WRFIFO(fdc, 6 | NE7_SPECIFY_NODMA);
+
+ fdc->sc_itask = FDC_ITASK_SENSEI;
+ /* seek function */
+ FDC_WRFIFO(fdc, NE7CMD_SEEK);
+ FDC_WRFIFO(fdc, fd->sc_drive); /* drive number */
+ FDC_WRFIFO(fdc, bp->b_cylin * fd->sc_type->step);
+
return (1);
case DOIO:
@@ -1291,10 +1399,10 @@ loop:
type = fd->sc_type;
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);
+ nblks = min(nblks, fd->sc_bcount / FD_BSIZE(fd));
+ nblks = min(nblks, FDC_MAXIOSIZE / FD_BSIZE(fd));
fd->sc_nblks = nblks;
- fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
+ fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FD_BSIZE(fd);
head = sec / type->sectrac;
sec -= head * type->sectrac;
#ifdef DIAGNOSTIC
@@ -1316,40 +1424,44 @@ loop:
*fdc->sc_reg_drs = type->rate;
#ifdef FD_DEBUG
if (fdc_debug > 1)
- printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
- read ? "read" : "write", fd->sc_drive,
- fd->sc_cylin, head, sec, nblks);
+ printf("fdcstate: doio: %s drive %d "
+ "track %d head %d sec %d nblks %d\n",
+ finfo ? "format" :
+ (read ? "read" : "write"),
+ fd->sc_drive, fd->sc_cylin, head, sec, nblks);
#endif
fdc->sc_state = IOCOMPLETE;
- fdc->sc_istate = ISTATE_DMA;
+ fdc->sc_itask = FDC_ITASK_DMA;
fdc->sc_nstat = 0;
+
+ disk_busy(&fd->sc_dk);
+
+ /* allow 3 seconds for operation */
+ timeout_add(&fdc->fdctimeout_to, 3 * hz);
+
if (finfo != NULL) {
/* formatting */
- OUT_FDC(fdc, NE7CMD_FORMAT, IOTIMEDOUT);
- OUT_FDC(fdc, (head << 2) | fd->sc_drive, IOTIMEDOUT);
- OUT_FDC(fdc, finfo->fd_formb_secshift, IOTIMEDOUT);
- OUT_FDC(fdc, finfo->fd_formb_nsecs, IOTIMEDOUT);
- OUT_FDC(fdc, finfo->fd_formb_gaplen, IOTIMEDOUT);
- OUT_FDC(fdc, finfo->fd_formb_fillbyte, IOTIMEDOUT);
+ FDC_WRFIFO(fdc, NE7CMD_FORMAT);
+ FDC_WRFIFO(fdc, (head << 2) | fd->sc_drive);
+ FDC_WRFIFO(fdc, finfo->fd_formb_secshift);
+ FDC_WRFIFO(fdc, finfo->fd_formb_nsecs);
+ FDC_WRFIFO(fdc, finfo->fd_formb_gaplen);
+ FDC_WRFIFO(fdc, finfo->fd_formb_fillbyte);
} else {
if (read)
- OUT_FDC(fdc, NE7CMD_READ, IOTIMEDOUT);
+ FDC_WRFIFO(fdc, NE7CMD_READ);
else
- OUT_FDC(fdc, NE7CMD_WRITE, IOTIMEDOUT);
- OUT_FDC(fdc, (head << 2) | fd->sc_drive, IOTIMEDOUT);
- OUT_FDC(fdc, fd->sc_cylin, IOTIMEDOUT); /*track*/
- OUT_FDC(fdc, head, IOTIMEDOUT);
- OUT_FDC(fdc, sec + 1, IOTIMEDOUT); /*sector+1*/
- OUT_FDC(fdc, type->secsize, IOTIMEDOUT);/*sector size*/
- OUT_FDC(fdc, type->sectrac, IOTIMEDOUT);/*secs/track*/
- OUT_FDC(fdc, type->gap1, IOTIMEDOUT); /*gap1 size*/
- OUT_FDC(fdc, type->datalen, IOTIMEDOUT);/*data length*/
+ FDC_WRFIFO(fdc, NE7CMD_WRITE);
+ FDC_WRFIFO(fdc, (head << 2) | fd->sc_drive);
+ FDC_WRFIFO(fdc, fd->sc_cylin); /*track*/
+ FDC_WRFIFO(fdc, head);
+ FDC_WRFIFO(fdc, sec + 1); /*sector+1*/
+ FDC_WRFIFO(fdc, type->secsize); /*sector size*/
+ FDC_WRFIFO(fdc, type->sectrac); /*secs/track*/
+ FDC_WRFIFO(fdc, type->gap1); /*gap1 size*/
+ FDC_WRFIFO(fdc, type->datalen); /*data length*/
}
- disk_busy(&fd->sc_dk);
-
- /* allow 2 seconds for operation */
- timeout_add(&fdc->fdctimeout_to, 2 * hz);
return (1); /* will return later */
case SEEKWAIT:
@@ -1369,7 +1481,7 @@ loop:
cyl != bp->b_cylin * fd->sc_type->step) {
#ifdef FD_DEBUG
if (fdc_debug)
- fdcstatus(&fd->sc_dv, 2, "seek failed");
+ fdcstatus(fdc, "seek failed");
#endif
fdcretry(fdc);
goto loop;
@@ -1378,12 +1490,35 @@ loop:
goto doio;
case IOTIMEDOUT:
- FTC_FLIP;
- (void)fdcresult(fdc);
- /*FALLTHROUGH*/
+ /*
+ * Try to abort the I/O operation without resetting
+ * the chip first. Poke TC and arrange to pick up
+ * the timed out I/O command's status.
+ */
+ fdc->sc_itask = FDC_ITASK_RESULT;
+ fdc->sc_state = IOCLEANUPWAIT;
+ fdc->sc_nstat = 0;
+ /* 1/10 second should be enough */
+ timeout_add(&fdc->fdctimeout_to, hz / 10);
+ return (1);
+
+ case IOCLEANUPTIMEDOUT:
case SEEKTIMEDOUT:
case RECALTIMEDOUT:
case RESETTIMEDOUT:
+ fdcstatus(fdc, "timeout");
+
+ /* All other timeouts always roll through a chip reset */
+ fdcretry(fdc);
+
+ /* Force reset, no matter what fdcretry() says */
+ fdc->sc_state = DORESET;
+ goto loop;
+
+ case IOCLEANUPWAIT: /* IO FAILED, cleanup succeeded */
+ timeout_del(&fdc->fdctimeout_to);
+ disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
+ (bp->b_flags & B_READ));
fdcretry(fdc);
goto loop;
@@ -1398,7 +1533,7 @@ loop:
((st0 & 0xf8) != 0x20 || (fdc->sc_cfg & CFG_EIS) == 0))) {
#ifdef FD_DEBUG
if (fdc_debug) {
- fdcstatus(&fd->sc_dv, 7,
+ fdcstatus(fdc,
bp->b_flags & B_READ
? "read failed" : "write failed");
printf("blkno %d nblks %d nstat %d tc %d\n",
@@ -1435,7 +1570,8 @@ loop:
}
if (fdc->sc_errors) {
diskerr(bp, "fd", "soft error", LOG_PRINTF,
- fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
+ fd->sc_skip / FD_BSIZE(fd),
+ (struct disklabel *)NULL);
printf("\n");
fdc->sc_errors = 0;
} else {
@@ -1465,30 +1601,29 @@ loop:
goto loop;
case DORESET:
- doreset:
/* try a reset, keep motor on */
fd_set_motor(fdc);
delay(100);
- fdc_reset(fdc);
fdc->sc_nstat = 0;
- fdc->sc_istate = ISTATE_SENSEI;
+ fdc->sc_itask = FDC_ITASK_SENSEI;
fdc->sc_state = RESETCOMPLETE;
timeout_add(&fdc->fdctimeout_to, hz / 2);
+ fdc_reset(fdc);
return (1); /* will return later */
case RESETCOMPLETE:
timeout_del(&fdc->fdctimeout_to);
fdconf(fdc);
- /* fall through */
+ /* FALLTHROUGH */
case DORECAL:
fdc->sc_state = RECALWAIT;
- fdc->sc_istate = ISTATE_SENSEI;
+ fdc->sc_itask = FDC_ITASK_SENSEI;
fdc->sc_nstat = 0;
- /* recalibrate function */
- OUT_FDC(fdc, NE7CMD_RECAL, RECALTIMEDOUT);
- OUT_FDC(fdc, fd->sc_drive, RECALTIMEDOUT);
timeout_add(&fdc->fdctimeout_to, 5 * hz);
+ /* recalibrate function */
+ FDC_WRFIFO(fdc, NE7CMD_RECAL);
+ FDC_WRFIFO(fdc, fd->sc_drive);
return (1); /* will return later */
case RECALWAIT:
@@ -1504,7 +1639,7 @@ loop:
if (fdc->sc_nstat != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
#ifdef FD_DEBUG
if (fdc_debug)
- fdcstatus(&fd->sc_dv, 2, "recalibrate failed");
+ fdcstatus(fdc, "recalibrate failed");
#endif
fdcretry(fdc);
goto loop;
@@ -1518,12 +1653,23 @@ loop:
goto doseek;
default:
- fdcstatus(&fd->sc_dv, 0, "stray interrupt");
+ fdcstatus(fdc, "stray interrupt");
return (1);
}
#ifdef DIAGNOSTIC
panic("fdcintr: impossible");
#endif
+
+xxx:
+ /*
+ * We get here if the chip locks up in FDC_WRFIFO()
+ * Cancel any operation and schedule a reset.
+ */
+ timeout_del(&fdc->fdctimeout_to);
+ fdcretry(fdc);
+ fdc->sc_state = DORESET;
+ goto loop;
+
#undef st0
#undef st1
#undef cyl
@@ -1535,6 +1681,7 @@ fdcretry(fdc)
{
struct fd_softc *fd;
struct buf *bp;
+ int error = EIO;
fd = fdc->sc_drives.tqh_first;
bp = fd->sc_q.b_actf;
@@ -1545,6 +1692,13 @@ fdcretry(fdc)
switch (fdc->sc_errors) {
case 0:
+ if (fdc->sc_nstat == 7 &&
+ (fdc->sc_status[0] & 0xd8) == 0x40 &&
+ (fdc->sc_status[1] & 0x2) == 0x2) {
+ printf("%s: read-only medium\n", fd->sc_dv.dv_xname);
+ error = EROFS;
+ goto failsilent;
+ }
/* try again */
fdc->sc_state =
(fdc->sc_flags & FDC_EIS) ? DOIO : DOSEEK;
@@ -1556,6 +1710,21 @@ fdcretry(fdc)
break;
case 4:
+ if (fdc->sc_nstat == 7 &&
+ fdc->sc_status[0] == 0 &&
+ fdc->sc_status[1] == 0 &&
+ fdc->sc_status[2] == 0) {
+ /*
+ * We've retried a few times and we've got
+ * valid status and all three status bytes
+ * are zero. Assume this condition is the
+ * result of no disk loaded into the drive.
+ */
+ printf("%s: no medium?\n", fd->sc_dv.dv_xname);
+ error = ENODEV;
+ goto failsilent;
+ }
+
/* still no go; reset the bastard */
fdc->sc_state = DORESET;
break;
@@ -1564,19 +1733,15 @@ fdcretry(fdc)
fail:
if ((fd->sc_opts & FDOPT_SILENT) == 0) {
diskerr(bp, "fd", "hard error", LOG_PRINTF,
- fd->sc_skip / FDC_BSIZE,
+ fd->sc_skip / FD_BSIZE(fd),
(struct disklabel *)NULL);
-
- printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n",
- fdc->sc_status[0], NE7_ST0BITS,
- fdc->sc_status[1], NE7_ST1BITS,
- fdc->sc_status[2], NE7_ST2BITS,
- fdc->sc_status[3], fdc->sc_status[4],
- fdc->sc_status[5]);
+ printf("\n");
+ fdcstatus(fdc, "controller status");
}
+ failsilent:
bp->b_flags |= B_ERROR;
- bp->b_error = EIO;
+ bp->b_error = error;
fdfinish(fd, bp);
}
fdc->sc_errors++;
@@ -1679,38 +1844,40 @@ fdioctl(dev, cmd, addr, flag, p)
fd->sc_opts = *(int *)addr;
return (0);
-#ifdef DEBUG
+#ifdef FD_DEBUG
case _IO('f', 100):
{
int i;
struct fdc_softc *fdc = (struct fdc_softc *)
fd->sc_dv.dv_parent;
- out_fdc(fdc, NE7CMD_DUMPREG);
+ fdc_wrfifo(fdc, NE7CMD_DUMPREG);
fdcresult(fdc);
printf("dumpreg(%d regs): <", fdc->sc_nstat);
for (i = 0; i < fdc->sc_nstat; i++)
- printf(" %x", fdc->sc_status[i]);
+ printf(" 0x%x", fdc->sc_status[i]);
printf(">\n");
}
return (0);
case _IOW('f', 101, int):
- ((struct fdc_softc *)fd->sc_dv.dv_parent)->sc_cfg &=
- ~CFG_THRHLD_MASK;
- ((struct fdc_softc *)fd->sc_dv.dv_parent)->sc_cfg |=
- (*(int *)addr & CFG_THRHLD_MASK);
- fdconf((struct fdc_softc *) fd->sc_dv.dv_parent);
+ {
+ struct fdc_softc *fdc = (struct fdc_softc *)
+ fd->sc_dv.dv_parent;
+ fdc->sc_cfg &= ~CFG_THRHLD_MASK;
+ fdc->sc_cfg |= (*(int *)addr & CFG_THRHLD_MASK);
+ fdconf(fdc);
+ }
return (0);
case _IO('f', 102):
{
int i;
struct fdc_softc *fdc = (struct fdc_softc *)
fd->sc_dv.dv_parent;
- out_fdc(fdc, NE7CMD_SENSEI);
+ fdc_wrfifo(fdc, NE7CMD_SENSEI);
fdcresult(fdc);
printf("sensei(%d regs): <", fdc->sc_nstat);
- for (i=0; i< fdc->sc_nstat; i++)
+ for (i = 0; i < fdc->sc_nstat; i++)
printf(" 0x%x", fdc->sc_status[i]);
}
printf(">\n");
@@ -1719,10 +1886,6 @@ fdioctl(dev, cmd, addr, flag, p)
default:
return (ENOTTY);
}
-
-#ifdef DIAGNOSTIC
- panic("fdioctl: impossible");
-#endif
}
int
@@ -1731,7 +1894,7 @@ fdformat(dev, finfo, p)
struct fd_formb *finfo;
struct proc *p;
{
- int rv = 0, s;
+ int rv = 0;
struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
struct fd_type *type = fd->sc_type;
struct buf *bp;
@@ -1751,40 +1914,43 @@ fdformat(dev, finfo, p)
* 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_blkno = ((finfo->cyl * (type->sectrac * type->heads)
+ + finfo->head * type->sectrac) * FD_BSIZE(fd))
+ / DEV_BSIZE;
bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
bp->b_data = (caddr_t)finfo;
#ifdef FD_DEBUG
- if (fdc_debug)
- printf("fdformat: blkno %x count %ld\n",
+ if (fdc_debug) {
+ int i;
+
+ printf("fdformat: blkno 0x%x count %ld\n",
bp->b_blkno, bp->b_bcount);
+
+ printf("\tcyl:\t%d\n", finfo->cyl);
+ printf("\thead:\t%d\n", finfo->head);
+ printf("\tnsecs:\t%d\n", finfo->fd_formb_nsecs);
+ printf("\tsshft:\t%d\n", finfo->fd_formb_secshift);
+ printf("\tgaplen:\t%d\n", finfo->fd_formb_gaplen);
+ printf("\ttrack data:");
+ for (i = 0; i < finfo->fd_formb_nsecs; i++) {
+ printf(" [c%d h%d s%d]",
+ finfo->fd_formb_cylno(i),
+ finfo->fd_formb_headno(i),
+ finfo->fd_formb_secno(i) );
+ if (finfo->fd_formb_secsize(i) != 2)
+ printf("<sz:%d>", finfo->fd_formb_secsize(i));
+ }
+ printf("\n");
+ }
#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", 20 * hz);
- if (rv == EWOULDBLOCK)
- break;
- }
- splx(s);
-
- if (rv == EWOULDBLOCK) {
- /* timed out */
- rv = EIO;
- s = splbio();
- biodone(bp);
- splx(s);
- }
- if (bp->b_flags & B_ERROR) {
- rv = bp->b_error;
- }
+ rv = biowait(bp);
PRELE(p);
free(bp, M_TEMP);
return (rv);
@@ -1803,17 +1969,17 @@ fdgetdisklabel(dev)
bzero(lp, sizeof(struct disklabel));
bzero(clp, sizeof(struct cpu_disklabel));
- lp->d_secsize = FDC_BSIZE;
+ lp->d_type = DTYPE_FLOPPY;
+ lp->d_secsize = FD_BSIZE(fd);
lp->d_secpercyl = fd->sc_type->seccyl;
- lp->d_ntracks = fd->sc_type->heads; /* Go figure... */
lp->d_nsectors = fd->sc_type->sectrac;
lp->d_ncylinders = fd->sc_type->tracks;
+ lp->d_ntracks = fd->sc_type->heads; /* Go figure... */
+ lp->d_secperunit = fd->sc_type->size;
+ lp->d_rpm = 300; /* XXX like it matters... */
strncpy(lp->d_typename, "floppy disk", sizeof(lp->d_typename));
- lp->d_type = DTYPE_FLOPPY;
strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
- lp->d_rpm = 300; /* XXX like it matters... */
- lp->d_secperunit = fd->sc_type->size;
lp->d_interleave = 1;
lp->d_flags = D_REMOVABLE;
@@ -1832,7 +1998,6 @@ fdgetdisklabel(dev)
errstring = readdisklabel(dev, fdstrategy, lp, clp, 0);
if (errstring) {
printf("%s: %s\n", fd->sc_dv.dv_xname, errstring);
- return;
}
}
@@ -1848,7 +2013,7 @@ fd_do_eject(fd)
auxregbisc(AUXIO4C_FEJ, AUXIO4C_FDS);
return;
}
- if (CPU_ISSUN4M && (fdc->sc_flags & FDC_82077)) {
+ if (CPU_ISSUN4M && (fdc->sc_flags & FDC_82077) != 0) {
int dor = FDO_FRST | FDO_FDMAEN | FDO_MOEN(0);
*fdc->sc_reg_dor = dor | FDO_EJ;
delay(10);
diff --git a/sys/arch/sparc/dev/fdreg.h b/sys/arch/sparc/dev/fdreg.h
index 3cf4138c1bb..cca36cd82de 100644
--- a/sys/arch/sparc/dev/fdreg.h
+++ b/sys/arch/sparc/dev/fdreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: fdreg.h,v 1.4 2003/06/02 23:27:54 millert Exp $ */
+/* $OpenBSD: fdreg.h,v 1.5 2004/09/22 22:12:58 miod Exp $ */
/* $NetBSD: fdreg.h,v 1.6 1997/05/02 13:03:44 pk Exp $ */
/*-
@@ -84,6 +84,7 @@ union fdreg {
#define FDO_DEN 0x40 /* Density select */
#define FDO_EJ 0x80 /* Eject disk */
+/* Digital Input Register bits */
#define FDI_DCHG 0x80 /* diskette has been changed */
/* XXX - find a place for these... */
diff --git a/sys/arch/sparc/dev/fdvar.h b/sys/arch/sparc/dev/fdvar.h
index c727ae374db..c3022021574 100644
--- a/sys/arch/sparc/dev/fdvar.h
+++ b/sys/arch/sparc/dev/fdvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: fdvar.h,v 1.5 1997/06/24 09:50:57 downsj Exp $ */
+/* $OpenBSD: fdvar.h,v 1.6 2004/09/22 22:12:58 miod Exp $ */
/*
* $NetBSD: fdvar.h,v 1.5 1996/12/08 23:40:34 pk Exp $
*
@@ -32,7 +32,7 @@
*
*/
-#define FDC_BSIZE 512
+#define FD_BSIZE(fd) (128 * (1 << fd->sc_type->secsize))
#define FDC_MAXIOSIZE NBPG /* XXX should be MAXBSIZE */
#define FDC_NSTATUS 10
@@ -50,7 +50,8 @@ struct fdcio {
/*
* Interrupt state.
*/
- int fdcio_istate;
+ int fdcio_itask;
+ int fdcio_istatus;
/*
* IO state.
@@ -67,12 +68,16 @@ struct fdcio {
};
#endif /* _LOCORE */
-/* istate values */
-#define ISTATE_IDLE 0 /* No HW interrupt expected */
-#define ISTATE_SPURIOUS 1 /* Spurious HW interrupt detected */
-#define ISTATE_SENSEI 2 /* Do SENSEI on next HW interrupt */
-#define ISTATE_DMA 3 /* Pseudo-DMA in progress */
-#define ISTATE_DONE 4 /* Interrupt processing complete */
+/* itask values */
+#define FDC_ITASK_NONE 0 /* No HW interrupt expected */
+#define FDC_ITASK_SENSEI 1 /* Do SENSEI on next HW interrupt */
+#define FDC_ITASK_DMA 2 /* Do Pseudo-DMA */
+#define FDC_ITASK_RESULT 3 /* Pick up command results */
-#define SUNOS_FDIOCEJECT _IO('f', 24)
+/* istatus values */
+#define FDC_ISTATUS_NONE 0 /* No status available */
+#define FDC_ISTATUS_SPURIOUS 1 /* Spurious HW interrupt detected */
+#define FDC_ISTATUS_ERROR 2 /* Operation completed abnormally */
+#define FDC_ISTATUS_DONE 3 /* Operation completed normally */
+#define SUNOS_FDIOCEJECT _IO('f', 24)
diff --git a/sys/arch/sparc/sparc/bsd_fdintr.s b/sys/arch/sparc/sparc/bsd_fdintr.s
index aeb2729f20b..547c72120da 100644
--- a/sys/arch/sparc/sparc/bsd_fdintr.s
+++ b/sys/arch/sparc/sparc/bsd_fdintr.s
@@ -1,4 +1,4 @@
-/* $OpenBSD: bsd_fdintr.s,v 1.9 2003/04/06 22:49:36 miod Exp $ */
+/* $OpenBSD: bsd_fdintr.s,v 1.10 2004/09/22 22:12:59 miod Exp $ */
/* $NetBSD: bsd_fdintr.s,v 1.11 1997/04/07 21:00:36 pk Exp $ */
/*
@@ -189,13 +189,16 @@ _C_LABEL(fdchwintr):
!!ld [R_fdc + FDC_REG_DOR], R_dor ! get chip DOR reg addr
! find out what we are supposed to do
- ld [R_fdc + FDC_ISTATE], %l7 ! examine flags
- cmp %l7, ISTATE_SENSEI
+ ld [R_fdc + FDC_ITASK], %l7 ! get task from fdc
+ cmp %l7, FDC_ITASK_SENSEI
be sensei
- nop
- cmp %l7, ISTATE_DMA
- bne spurious
- nop
+ !nop
+ cmp %l7, FDC_ITASK_RESULT
+ be resultphase
+ !nop
+ cmp %l7, FDC_ITASK_DMA
+ bne,a ssi ! a spurious interrupt
+ mov FDC_ISTATUS_SPURIOUS, %l7 ! set status and post sw intr
! pseudo DMA
ld [R_fdc + FDC_TC], R_tc ! residual count
@@ -245,16 +248,12 @@ nextc:
FD_DEASSERT_TC
b,a resultphase1
-spurious:
- mov ISTATE_SPURIOUS, %l7
- st %l7, [R_fdc + FDC_ISTATE]
- b,a ssi
-
sensei:
ldub [R_msr], %l7
set POLL_TIMO, %l6
1: deccc %l6 ! timeout?
- be ssi
+ be,a ssi ! if so, set status
+ mov FDC_ISTATUS_ERROR, %l7 ! and post sw interrupt
and %l7, (NE7_RQM | NE7_DIO | NE7_CB), %l7
cmp %l7, NE7_RQM
bne,a 1b ! loop till chip ready
@@ -273,7 +272,8 @@ resultphase1:
ldub [R_msr], %l7
set POLL_TIMO, %l6
1: deccc %l6 ! timeout?
- be ssi
+ be,a ssi ! if so, set status
+ mov FDC_ISTATUS_ERROR, %l7 ! and post sw interrupt
and %l7, (NE7_RQM | NE7_DIO | NE7_CB), %l7
cmp %l7, NE7_RQM
be 3f ! done
@@ -293,11 +293,12 @@ resultphase1:
3:
! got status, update sc_nstat and mark istate DONE
st R_stcnt, [R_fdc + FDC_NSTAT]
- mov ISTATE_DONE, %l7
- st %l7, [R_fdc + FDC_ISTATE]
+ mov FDC_ISTATUS_DONE, %l7
ssi:
! set software interrupt
+ ! enter here with status in %l7
+ st %l7, [R_fdc + FDC_ISTATUS]
FD_SET_SWINTR
x:
diff --git a/sys/arch/sparc/sparc/genassym.cf b/sys/arch/sparc/sparc/genassym.cf
index 71660d9efde..7fc9e86d9a0 100644
--- a/sys/arch/sparc/sparc/genassym.cf
+++ b/sys/arch/sparc/sparc/genassym.cf
@@ -1,4 +1,4 @@
-# $OpenBSD: genassym.cf,v 1.15 2004/06/13 21:49:20 niklas Exp $
+# $OpenBSD: genassym.cf,v 1.16 2004/09/22 22:12:59 miod Exp $
# $NetBSD: genassym.cf,v 1.2 1997/06/28 19:59:04 pk Exp $
#
@@ -208,7 +208,8 @@ member HALT exitToMon
struct fdcio
member FDC_REG_MSR fdcio_reg_msr
member FDC_REG_FIFO fdcio_reg_fifo
-member FDC_ISTATE fdcio_istate
+member FDC_ITASK fdcio_itask
+member FDC_ISTATUS fdcio_istatus
member FDC_STATUS fdcio_status
member FDC_NSTAT fdcio_nstat
member FDC_DATA fdcio_data