diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2004-09-22 22:13:00 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2004-09-22 22:13:00 +0000 |
commit | f3ecf07ff4fd224ca32417039ccb99d8532ec9ac (patch) | |
tree | b6f8aece36832624c9052889bfe5795b335a3b5d /sys/arch | |
parent | ea075872881abbf59bd05df6aa7635696fe3e426 (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.
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/sparc/dev/fd.c | 657 | ||||
-rw-r--r-- | sys/arch/sparc/dev/fdreg.h | 3 | ||||
-rw-r--r-- | sys/arch/sparc/dev/fdvar.h | 25 | ||||
-rw-r--r-- | sys/arch/sparc/sparc/bsd_fdintr.s | 33 | ||||
-rw-r--r-- | sys/arch/sparc/sparc/genassym.cf | 5 |
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 |