diff options
Diffstat (limited to 'sys/arch/sparc/dev')
-rw-r--r-- | sys/arch/sparc/dev/fd.c | 489 | ||||
-rw-r--r-- | sys/arch/sparc/dev/fdreg.h | 15 | ||||
-rw-r--r-- | sys/arch/sparc/dev/fdvar.h | 5 |
3 files changed, 335 insertions, 174 deletions
diff --git a/sys/arch/sparc/dev/fd.c b/sys/arch/sparc/dev/fd.c index c703e19e963..92db72bac52 100644 --- a/sys/arch/sparc/dev/fd.c +++ b/sys/arch/sparc/dev/fd.c @@ -1,5 +1,5 @@ -/* $OpenBSD: fd.c,v 1.17 1997/05/30 08:27:49 grr Exp $ */ -/* $NetBSD: fd.c,v 1.33.4.1 1996/06/12 20:52:25 pk Exp $ */ +/* $OpenBSD: fd.c,v 1.18 1997/06/24 09:50:56 downsj Exp $ */ +/* $NetBSD: fd.c,v 1.51 1997/05/24 20:16:19 pk Exp $ */ /*- * Copyright (c) 1993, 1994, 1995 Charles Hannum. @@ -10,6 +10,12 @@ * This code is derived from software contributed to Berkeley by * Don Ahn. * + * Portions Copyright (c) 1993, 1994 by + * jc@irbs.UUCP (John Capo) + * vak@zebub.msk.su (Serge Vakulenko) + * ache@astral.msk.su (Andrew A. Chernov) + * joerg_wunsch@uriah.sax.de (Joerg Wunsch) + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -51,6 +57,8 @@ #include <sys/dkstat.h> #include <sys/disk.h> #include <sys/buf.h> +#include <sys/malloc.h> +#include <sys/proc.h> #include <sys/uio.h> #include <sys/mtio.h> #include <sys/stat.h> @@ -63,6 +71,7 @@ #include <machine/cpu.h> #include <machine/autoconf.h> #include <machine/conf.h> +#include <machine/ioctl_fd.h> #include <sparc/sparc/auxreg.h> #include <sparc/dev/fdreg.h> @@ -72,6 +81,9 @@ #define FDTYPE(dev) ((minor(dev) & 0x70) >> 4) #define FDPART(dev) (minor(dev) & 0x0f) +/* XXX misuse a flag to identify format operation */ +#define B_FORMAT B_XXX + #define b_cylin b_resid #define FD_DEBUG @@ -145,35 +157,15 @@ struct cfdriver fdc_cd = { __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t)); -/* - * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how - * we tell them apart. - */ -struct fd_type { - int sectrac; /* sectors per track */ - int heads; /* number of heads */ - int seccyl; /* sectors per cylinder */ - int secsize; /* size code for sectors */ - int datalen; /* data len when secsize = 0 */ - int steprate; /* step rate and head unload time */ - int gap1; /* gap len between sectors */ - int gap2; /* formatting gap */ - int tracks; /* total num of tracks */ - int size; /* size of disk in sectors */ - int step; /* steps per cylinder */ - int rate; /* transfer speed code */ - char *name; -}; - /* 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 */ - { 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 */ + { 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 */ + { 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 */ }; /* software state, per disk (with up to 4 disks per ctlr) */ @@ -196,6 +188,7 @@ struct fd_softc { #define FD_MOTOR 0x02 /* motor should be on */ #define FD_MOTOR_WAIT 0x04 /* motor coming up */ int sc_cylin; /* where we think the head is */ + int sc_opts; /* user-set options */ void *sc_sdhook; /* shutdownhook cookie */ @@ -241,9 +234,11 @@ int fdchwintr __P((struct fdc_softc *)); void fdchwintr __P((void)); #endif int fdcswintr __P((struct fdc_softc *)); +int fdcstate __P((struct fdc_softc *)); void fdcretry __P((struct fdc_softc *fdc)); void fdfinish __P((struct fd_softc *fd, struct buf *bp)); -void fd_do_eject __P((void)); +int fdformat __P((dev_t, struct fd_formb *, struct proc *)); +void fd_do_eject __P((struct fd_softc *)); void fd_mountroot_hook __P((struct device *)); static void fdconf __P((struct fdc_softc *)); @@ -253,6 +248,19 @@ static void fdconf __P((struct fdc_softc *)); #error 4 #endif +#ifdef FDC_C_HANDLER +#if defined(SUN4M) +#define FD_SET_SWINTR do { \ + if (CPU_ISSUN4M) \ + raise(0, PIL_FDSOFT); \ + else \ + ienab_bis(IE_L4); \ +} while(0) +#else +#define AUDIO_SET_SWINTR ienab_bis(IE_FDSOFT) +#endif /* defined(SUN4M) */ +#endif /* FDC_C_HANDLER */ + #define OBP_FDNAME (CPU_ISSUN4M ? "SUNW,fdtwo" : "fd") int @@ -281,14 +289,6 @@ fdcmatch(parent, match, aux) if ((CPU_ISSUN4M) && (ca->ca_bustype != BUS_OBIO)) return (0); -#ifndef FDSUN4M - /* - * XXX Floppy doesn't work yet sun4m, nasty things happen if you try - */ - if (CPU_ISSUN4M) - return (0); -#endif - /* Sun PROMs call the controller an "fd" or "SUNW,fdtwo" */ if (strcmp(OBP_FDNAME, ra->ra_name)) return (0); @@ -326,7 +326,7 @@ fdprint(aux, fdc) if (!fdc) printf(" drive %d", fa->fa_drive); - return QUIET; + return (QUIET); } static void @@ -447,27 +447,35 @@ fdcattach(parent, self, aux) */ fa.fa_bootpath = 0; if ((bp = ca->ca_ra.ra_bp) && strcmp(bp->name, OBP_FDNAME) == 0) { - /* - * WOAH THERE! It looks like we can get the bootpath - * in several different formats!! The faked - * bootpath (and some v2?) looks like /fd@0,0 - * but the real bootpath on some v2 OpenPROM - * systems looks like /fd0. In the case of - * a floppy controller on obio (such as on the sun4m), - * we use "slot, offset" to determine if this is the - * right one. --thorpej - */ + switch (ca->ca_bustype) { case BUS_MAIN: - if (((bp->val[0] == 0) && /* /fd@0,0 */ + /* + * We can get the bootpath in several different + * formats! The faked v1 bootpath looks like /fd@0,0. + * The v2 bootpath is either just /fd0, in which case + * `bp->val[0]' will have been set to -1, or /fd@x,y + * where <x,y> is the prom address specifier. + */ + if (((bp->val[0] == ca->ca_ra.ra_iospace) && + (bp->val[1] == (int)ca->ca_ra.ra_paddr)) || + + ((bp->val[0] == -1) && /* v2: /fd0 */ (bp->val[1] == 0)) || - ((bp->val[0] == -1) && /* /fd0 */ - (bp->val[1] == 0))) + + ((bp->val[0] == 0) && /* v1: /fd@0,0 */ + (bp->val[1] == 0)) + ) fa.fa_bootpath = bp; break; case BUS_OBIO: - /* /obio0/SUNW,fdtwo@0,700000 */ + /* + * floppy controller on obio (such as on the sun4m), + * e.g.: `/obio0/SUNW,fdtwo@0,700000'. + * We use "slot, offset" to determine if this is the + * right one. + */ if ((bp->val[0] == ca->ca_slot) && (bp->val[1] == ca->ca_offset)) fa.fa_bootpath = bp; @@ -500,14 +508,14 @@ fdmatch(parent, match, aux) int n, ok; if (drive > 0) - /* XXX - for now, punt > 1 drives */ - return 0; + /* XXX - for now, punt on more than one drive */ + return (0); if (fdc->sc_flags & FDC_82077) { /* select drive and turn on motor */ *fdc->sc_reg_dor = drive | FDO_FRST | FDO_MOEN(drive); } else { - auxregbisc(AUXIO_FDS, 0); + auxregbisc(AUXIO4C_FDS, 0); } /* wait for motor to spin up */ delay(250000); @@ -546,12 +554,14 @@ fdmatch(parent, match, aux) ok = (n == 2 && (fdc->sc_status[0] & 0xf8) == 0x20) ? 1 : 0; /* turn off motor */ - if (fdc->sc_flags & FDC_82077) - *fdc->sc_reg_dor = FDO_FRST; - else - auxregbisc(0, AUXIO_FDS); + if (fdc->sc_flags & FDC_82077) { + /* deselect drive and turn motor off */ + *fdc->sc_reg_dor = FDO_FRST | FDO_DS; + } else { + auxregbisc(0, AUXIO4C_FDS); + } - return ok; + return (ok); } /* @@ -571,7 +581,7 @@ fdattach(parent, self, aux) /* XXX Allow `flags' to override device type? */ if (type) - printf(": %s, %d cyl, %d head, %d sec\n", type->name, + printf(": %s %d cyl, %d head, %d sec\n", type->name, type->tracks, type->heads, type->sectrac); else printf(": density unknown\n"); @@ -581,6 +591,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); + /* * Initialize and attach the disk structure. */ @@ -615,8 +629,8 @@ fd_dev_to_type(fd, dev) int type = FDTYPE(dev); if (type > (sizeof(fd_types) / sizeof(fd_types[0]))) - return NULL; - return type ? &fd_types[type - 1] : fd->sc_deftype; + return (NULL); + return (type ? &fd_types[type - 1] : fd->sc_deftype); } void @@ -632,7 +646,8 @@ fdstrategy(bp) if (unit >= fd_cd.cd_ndevs || (fd = fd_cd.cd_devs[unit]) == 0 || bp->b_blkno < 0 || - (bp->b_bcount % FDC_BSIZE) != 0) { + ((bp->b_bcount % FDC_BSIZE) != 0 && + (bp->b_flags & B_FORMAT) == 0)) { bp->b_error = EINVAL; goto bad; } @@ -744,12 +759,16 @@ fdc_reset(fdc) struct fdc_softc *fdc; { if (fdc->sc_flags & FDC_82077) { - *fdc->sc_reg_dor = FDO_MOEN(0); + *fdc->sc_reg_dor = FDO_FDMAEN | FDO_MOEN(0); } *fdc->sc_reg_drs = DRS_RESET; delay(10); *fdc->sc_reg_drs = 0; + + if (fdc->sc_flags & FDC_82077) { + *fdc->sc_reg_dor = FDO_FRST | FDO_FDMAEN | FDO_DS; + } #ifdef FD_DEBUG if (fdc_debug) printf("fdc reset\n"); @@ -780,9 +799,9 @@ fd_set_motor(fdc) if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) on = 1; if (on) { - auxregbisc(AUXIO_FDS, 0); + auxregbisc(AUXIO4C_FDS, 0); } else { - auxregbisc(0, AUXIO_FDS); + auxregbisc(0, AUXIO4C_FDS); } } } @@ -811,7 +830,7 @@ fd_motor_on(arg) s = splbio(); fd->sc_flags &= ~FD_MOTOR_WAIT; if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT)) - (void) fdcswintr(fdc); + (void) fdcstate(fdc); splx(s); } @@ -830,10 +849,11 @@ fdcresult(fdc) if (i == (NE7_DIO | NE7_RQM | NE7_CB)) { if (n >= sizeof(fdc->sc_status)) { log(LOG_ERR, "fdcresult: overrun\n"); - return -1; + return (-1); } fdc->sc_status[n++] = *fdc->sc_reg_fifo; - } + } else + delay(10); } log(LOG_ERR, "fdcresult: timeout\n"); return (fdc->sc_nstat = -1); @@ -846,12 +866,13 @@ out_fdc(fdc, x) { int i = 100000; - while (((*fdc->sc_reg_msr & (NE7_DIO|NE7_RQM)) != NE7_RQM) && i-- > 0); + while (((*fdc->sc_reg_msr & (NE7_DIO|NE7_RQM)) != NE7_RQM) && i-- > 0) + delay(1); if (i <= 0) - return -1; + return (-1); *fdc->sc_reg_fifo = x; - return 0; + return (0); } int @@ -866,17 +887,17 @@ fdopen(dev, flags, fmt, p) unit = FDUNIT(dev); if (unit >= fd_cd.cd_ndevs) - return ENXIO; + return (ENXIO); fd = fd_cd.cd_devs[unit]; if (fd == 0) - return ENXIO; + return (ENXIO); type = fd_dev_to_type(fd, dev); if (type == NULL) - return ENXIO; + return (ENXIO); if ((fd->sc_flags & FD_OPEN) != 0 && fd->sc_type != type) - return EBUSY; + return (EBUSY); fd->sc_type = type; fd->sc_cylin = -1; @@ -902,7 +923,7 @@ fdopen(dev, flags, fmt, p) fd->sc_dk.dk_openmask = fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask; - return 0; + return (0); } int @@ -915,6 +936,7 @@ fdclose(dev, flags, fmt, p) int pmask = (1 << FDPART(dev)); fd->sc_flags &= ~FD_OPEN; + fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT); switch (fmt) { case S_IFCHR: @@ -928,7 +950,7 @@ fdclose(dev, flags, fmt, p) fd->sc_dk.dk_openmask = fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask; - return 0; + return (0); } int @@ -964,7 +986,7 @@ fdcstart(fdc) return; } #endif - (void) fdcswintr(fdc); + (void) fdcstate(fdc); } void @@ -974,6 +996,7 @@ fdcstatus(dv, n, s) char *s; { struct fdc_softc *fdc = (void *)dv->dv_parent; + char bits[64]; #if 0 /* * A 82072 seems to return <invalid command> on @@ -996,7 +1019,7 @@ fdcstatus(dv, n, s) printf("\n"); break; case 2: - printf(" (st0 %b cyl %d)\n", + printf(" (st0 %s cyl %d)\n", fdc->sc_status[0], NE7_ST0BITS, fdc->sc_status[1]); break; @@ -1031,7 +1054,7 @@ fdctimeout(arg) else fdc->sc_state = DEVIDLE; - (void) fdcswintr(fdc); + (void) fdcstate(fdc); splx(s); } @@ -1044,7 +1067,7 @@ fdcpseudointr(arg) /* Just ensure it has the right spl. */ s = splbio(); - (void) fdcswintr(fdc); + (void) fdcstate(fdc); splx(s); } @@ -1058,23 +1081,21 @@ int fdchwintr(fdc) struct fdc_softc *fdc; { - struct buf *bp; - int read; switch (fdc->sc_istate) { + case ISTATE_IDLE: + return (0); case ISTATE_SENSEI: out_fdc(fdc, NE7CMD_SENSEI); fdcresult(fdc); fdc->sc_istate = ISTATE_IDLE; - ienab_bis(IE_FDSOFT); + FD_SET_SWINTR; goto done; - case ISTATE_IDLE: case ISTATE_SPURIOUS: - auxregbisc(0, AUXIO_FDS); /* Does this help? */ fdcresult(fdc); fdc->sc_istate = ISTATE_SPURIOUS; printf("fdc: stray hard interrupt... "); - ienab_bis(IE_FDSOFT); + FD_SET_SWINTR; goto done; case ISTATE_DMA: break; @@ -1083,7 +1104,6 @@ fdchwintr(fdc) goto done; } - read = bp->b_flags & B_READ; for (;;) { register int msr; @@ -1101,25 +1121,15 @@ fdchwintr(fdc) } if (msr & NE7_DIO) { -#ifdef DIAGNOSTIC - if (!read) - printf("fdxfer: false read\n"); -#endif *fdc->sc_data++ = *fdc->sc_reg_fifo; } else { -#ifdef DIAGNOSTIC - if (read) - printf("fdxfer: false write\n"); -#endif *fdc->sc_reg_fifo = *fdc->sc_data++; } if (--fdc->sc_tc == 0) { - auxregbisc(AUXIO_FTC, 0); - fdc->sc_istate = ISTATE_IDLE; - delay(10); - auxregbisc(0, AUXIO_FTC); + fdc->sc_istate = ISTATE_DONE; + FTC_FLIP; fdcresult(fdc); - ienab_bis(IE_FDSOFT); + FD_SET_SWINTR; break; } } @@ -1133,6 +1143,22 @@ int fdcswintr(fdc) struct fdc_softc *fdc; { + int s; + + if (fdc->sc_istate != ISTATE_DONE) + return (0); + + fdc->sc_istate = ISTATE_IDLE; + s = splbio(); + fdcstate(fdc); + splx(s); + return (1); +} + +int +fdcstate(fdc) + struct fdc_softc *fdc; +{ #define st0 fdc->sc_status[0] #define st1 fdc->sc_status[1] #define cyl fdc->sc_status[1] @@ -1143,6 +1169,7 @@ fdcswintr(fdc) struct buf *bp; int read, head, sec, nblks; struct fd_type *type; + struct fd_formb *finfo = NULL; if (fdc->sc_istate != ISTATE_IDLE) { @@ -1162,7 +1189,7 @@ loop: fd = fdc->sc_drives.tqh_first; if (fd == NULL) { fdc->sc_state = DEVIDLE; - return 0; + return (0); } /* Is there a transfer to this drive? If not, deactivate drive. */ @@ -1174,6 +1201,9 @@ loop: goto loop; } + if (bp->b_flags & B_FORMAT) + finfo = (struct fd_formb *)bp->b_data; + switch (fdc->sc_state) { case DEVIDLE: fdc->sc_errors = 0; @@ -1183,7 +1213,7 @@ loop: untimeout(fd_motor_off, fd); if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) { fdc->sc_state = MOTORWAIT; - return 1; + return (1); } if ((fd->sc_flags & FD_MOTOR) == 0) { /* Turn on the motor, being careful about pairing. */ @@ -1202,15 +1232,16 @@ loop: fd->sc_flags &= ~FD_MOTOR_WAIT; goto loop; } - return 1; + return (1); } /* Make sure the right drive is selected. */ fd_set_motor(fdc); - /* fall through */ + /*FALLTHROUGH*/ case DOSEEK: doseek: - if (fdc->sc_flags & FDC_EIS) { + if ((fdc->sc_flags & FDC_EIS) && + (bp->b_flags & B_FORMAT) == 0) { fd->sc_cylin = bp->b_cylin; /* We use implied seek */ goto doio; @@ -1222,7 +1253,8 @@ loop: /* specify command */ OUT_FDC(fdc, NE7CMD_SPECIFY, SEEKTIMEDOUT); OUT_FDC(fdc, fd->sc_type->steprate, SEEKTIMEDOUT); - OUT_FDC(fdc, 6, SEEKTIMEDOUT); /* XXX head load time == 6ms */ + /* XXX head load time == 6ms */ + OUT_FDC(fdc, 6 | NE7_SPECIFY_NODMA, SEEKTIMEDOUT); fdc->sc_istate = ISTATE_SENSEI; /* seek function */ @@ -1238,17 +1270,20 @@ loop: disk_busy(&fd->sc_dk); timeout(fdctimeout, fdc, 4 * hz); - return 1; + return (1); case DOIO: doio: + if (finfo != NULL) + fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) - + (char *)finfo; 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); fd->sc_nblks = nblks; - fd->sc_nbytes = nblks * FDC_BSIZE; + fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE; head = sec / type->sectrac; sec -= head * type->sectrac; #ifdef DIAGNOSTIC @@ -1277,24 +1312,34 @@ loop: fdc->sc_state = IOCOMPLETE; fdc->sc_istate = ISTATE_DMA; fdc->sc_nstat = 0; - if (read) - OUT_FDC(fdc, NE7CMD_READ, IOTIMEDOUT); /* READ */ - else - OUT_FDC(fdc, NE7CMD_WRITE, IOTIMEDOUT); /* WRITE */ - 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);/* sectors/track */ - OUT_FDC(fdc, type->gap1, IOTIMEDOUT); /* gap1 size */ - OUT_FDC(fdc, type->datalen, IOTIMEDOUT);/* data length */ + 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); + } else { + if (read) + OUT_FDC(fdc, NE7CMD_READ, IOTIMEDOUT); + 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*/ + } disk_busy(&fd->sc_dk); /* allow 2 seconds for operation */ timeout(fdctimeout, fdc, 2 * hz); - return 1; /* will return later */ + return (1); /* will return later */ case SEEKWAIT: untimeout(fdctimeout, fdc); @@ -1302,9 +1347,9 @@ loop: if (fdc->sc_flags & FDC_NEEDHEADSETTLE) { /* allow 1/50 second for heads to settle */ timeout(fdcpseudointr, fdc, hz / 50); - return 1; /* will return later */ + return (1); /* will return later */ } - + /*FALLTHROUGH*/ case SEEKCOMPLETE: disk_unbusy(&fd->sc_dk, 0); /* no data on seek */ @@ -1322,10 +1367,9 @@ loop: goto doio; case IOTIMEDOUT: - auxregbisc(AUXIO_FTC, 0); - delay(10); - auxregbisc(0, AUXIO_FTC); + FTC_FLIP; (void)fdcresult(fdc); + /*FALLTHROUGH*/ case SEEKTIMEDOUT: case RECALTIMEDOUT: case RESETTIMEDOUT: @@ -1337,14 +1381,17 @@ loop: disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid)); - if (fdc->sc_nstat != 7 || (st0 & 0xf8) != 0 || st1 != 0) { + if (fdc->sc_nstat != 7 || st1 != 0 || + ((st0 & 0xf8) != 0 && + ((st0 & 0xf8) != 0x20 || (fdc->sc_cfg & CFG_EIS) == 0))) { #ifdef FD_DEBUG if (fdc_debug) { fdcstatus(&fd->sc_dv, 7, bp->b_flags & B_READ ? "read failed" : "write failed"); - printf("blkno %d nblks %d tc %d\n", - fd->sc_blkno, fd->sc_nblks, fdc->sc_tc); + printf("blkno %d nblks %d nstat %d tc %d\n", + fd->sc_blkno, fd->sc_nblks, + fdc->sc_nstat, fdc->sc_tc); } #endif if (fdc->sc_nstat == 7 && @@ -1398,7 +1445,7 @@ loop: fd->sc_blkno += fd->sc_nblks; fd->sc_skip += fd->sc_nbytes; fd->sc_bcount -= fd->sc_nbytes; - if (fd->sc_bcount > 0) { + if (finfo == NULL && fd->sc_bcount > 0) { bp->b_cylin = fd->sc_blkno / fd->sc_type->seccyl; goto doseek; } @@ -1415,7 +1462,7 @@ loop: fdc->sc_istate = ISTATE_SENSEI; fdc->sc_state = RESETCOMPLETE; timeout(fdctimeout, fdc, hz / 2); - return 1; /* will return later */ + return (1); /* will return later */ case RESETCOMPLETE: untimeout(fdctimeout, fdc); @@ -1430,7 +1477,7 @@ loop: OUT_FDC(fdc, NE7CMD_RECAL, RECALTIMEDOUT); OUT_FDC(fdc, fd->sc_drive, RECALTIMEDOUT); timeout(fdctimeout, fdc, 5 * hz); - return 1; /* will return later */ + return (1); /* will return later */ case RECALWAIT: untimeout(fdctimeout, fdc); @@ -1438,7 +1485,7 @@ loop: if (fdc->sc_flags & FDC_NEEDHEADSETTLE) { /* allow 1/30 second for heads to settle */ timeout(fdcpseudointr, fdc, hz / 30); - return 1; /* will return later */ + return (1); /* will return later */ } case RECALCOMPLETE: @@ -1455,12 +1502,12 @@ loop: case MOTORWAIT: if (fd->sc_flags & FD_MOTOR_WAIT) - return 1; /* time's not up yet */ + return (1); /* time's not up yet */ goto doseek; default: fdcstatus(&fd->sc_dv, 0, "stray interrupt"); - return 1; + return (1); } #ifdef DIAGNOSTIC panic("fdcintr: impossible"); @@ -1474,6 +1521,7 @@ void fdcretry(fdc) struct fdc_softc *fdc; { + char bits[64]; struct fd_softc *fd; struct buf *bp; @@ -1481,6 +1529,8 @@ fdcretry(fdc) bp = fd->sc_q.b_actf; fdc->sc_overruns = 0; + if (fd->sc_opts & FDOPT_NORETRY) + goto fail; switch (fdc->sc_errors) { case 0: @@ -1500,14 +1550,19 @@ fdcretry(fdc) break; default: - diskerr(bp, "fd", "hard error", LOG_PRINTF, - fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL); - - printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n", - 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]); + fail: + if ((fd->sc_opts & FDOPT_SILENT) == 0) { + diskerr(bp, "fd", "hard error", LOG_PRINTF, + fd->sc_skip / FDC_BSIZE, + (struct disklabel *)NULL); + + printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n", + 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]); + } bp->b_flags |= B_ERROR; bp->b_error = EIO; @@ -1522,7 +1577,7 @@ fdsize(dev) { /* Swapping to floppies would not make sense. */ - return -1; + return (-1); } int @@ -1534,7 +1589,7 @@ fddump(dev, blkno, va, size) { /* Not implemented. */ - return EINVAL; + return (EINVAL); } int @@ -1546,6 +1601,11 @@ fdioctl(dev, cmd, addr, flag, p) struct proc *p; { struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; + struct fdformat_parms *form_parms; + struct fdformat_cmd *form_cmd; + struct fd_formb fd_formbbuf; + int il[FD_MAX_NSEC + 1]; + int i, j; int error; switch (cmd) { @@ -1557,28 +1617,28 @@ fdioctl(dev, cmd, addr, flag, p) if ((flag & FWRITE) == 0) return EBADF; /* XXX do something */ - return 0; + return (0); case DIOCWDINFO: if ((flag & FWRITE) == 0) - return EBADF; + return (EBADF); error = setdisklabel(fd->sc_dk.dk_label, (struct disklabel *)addr, 0, fd->sc_dk.dk_cpulabel); if (error) - return error; + return (error); error = writedisklabel(dev, fdstrategy, fd->sc_dk.dk_label, fd->sc_dk.dk_cpulabel); - return error; + return (error); case DIOCLOCK: /* * Nothing to do here, really. */ - return 0; + return (0); case MTIOCTOP: if (((struct mtop *)addr)->mt_op != MTOFFL) @@ -1588,8 +1648,30 @@ fdioctl(dev, cmd, addr, flag, p) case SUNOS_FDIOCEJECT: #endif case DIOCEJECT: - fd_do_eject(); - return 0; + fd_do_eject(fd); + return (0); + + case FD_FORM: + if((flag & FWRITE) == 0) + return EBADF; /* must be opened for writing */ + else if(((struct fd_formb *)addr)->format_version != + FD_FORMAT_VERSION) + return EINVAL; /* wrong version of formatting prog */ + else + return fdformat(dev, (struct fd_formb *)addr, p); + break; + + case FD_GTYPE: /* get drive type */ + *(struct fd_type *)addr = *fd->sc_type; + return (0); + + case FD_GOPTS: /* get drive options */ + *(int *)addr = fd->sc_opts; + return (0); + + case FD_SOPTS: /* set drive options */ + fd->sc_opts = *(int *)addr; + return (0); #ifdef DEBUG case _IO('f', 100): @@ -1606,14 +1688,14 @@ fdioctl(dev, cmd, addr, flag, p) printf(">\n"); } - return 0; + 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); - return 0; + return (0); case _IO('f', 102): { int i; @@ -1626,10 +1708,10 @@ fdioctl(dev, cmd, addr, flag, p) printf(" 0x%x", fdc->sc_status[i]); } printf(">\n"); - return 0; + return (0); #endif default: - return ENOTTY; + return (ENOTTY); } #ifdef DIAGNOSTIC @@ -1637,6 +1719,69 @@ fdioctl(dev, cmd, addr, flag, p) #endif } +int +fdformat(dev, finfo, p) + dev_t dev; + struct fd_formb *finfo; + struct proc *p; +{ + int rv = 0, s; + struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; + struct fd_type *type = fd->sc_type; + struct buf *bp; + + /* set up a buffer header for fdstrategy() */ + bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT); + if (bp == 0) + return (ENOBUFS); + + PHOLD(p); + bzero((void *)bp, sizeof(struct buf)); + bp->b_flags = B_BUSY | B_PHYS | B_FORMAT; + bp->b_proc = p; + bp->b_dev = dev; + + /* + * Calculate a fake blkno, so fdstrategy() would initiate a + * seek to the requested cylinder. + */ + bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads) + + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE; + + bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; + bp->b_data = (caddr_t)finfo; + +#ifdef FD_DEBUG + if (fdc_debug) + printf("fdformat: blkno %x count %ld\n", + bp->b_blkno, bp->b_bcount); +#endif + + /* now do the format */ + fdstrategy(bp); + + /* ...and wait for it to complete */ + s = splbio(); + while (!(bp->b_flags & B_DONE)) { + rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz); + if (rv == EWOULDBLOCK) + break; + } + splx(s); + + if (rv == EWOULDBLOCK) { + /* timed out */ + rv = EIO; + biodone(bp); + } + if (bp->b_flags & B_ERROR) { + rv = bp->b_error; + } + PRELE(p); + free(bp, M_TEMP); + return (rv); +} + void fdgetdisklabel(dev) dev_t dev; @@ -1684,12 +1829,24 @@ fdgetdisklabel(dev) } void -fd_do_eject() +fd_do_eject(fd) + struct fd_softc *fd; { + struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent; - auxregbisc(AUXIO_FDS, AUXIO_FEJ); - delay(10); - auxregbisc(AUXIO_FEJ, AUXIO_FDS); + if (CPU_ISSUN4C) { + auxregbisc(AUXIO4C_FDS, AUXIO4C_FEJ); + delay(10); + auxregbisc(AUXIO4C_FEJ, AUXIO4C_FDS); + return; + } + if (CPU_ISSUN4M && (fdc->sc_flags & FDC_82077)) { + int dor = FDO_FRST | FDO_FDMAEN | FDO_MOEN(0); + *fdc->sc_reg_dor = dor | FDO_EJ; + delay(10); + *fdc->sc_reg_dor = FDO_FRST | FDO_DS; + return; + } } /* @@ -1705,7 +1862,7 @@ fd_mountroot_hook(dev) { int c; - fd_do_eject(); + fd_do_eject((struct fd_softc *)dev); if (dev) { printf("Insert filesystem floppy and press return."); @@ -1713,7 +1870,7 @@ fd_mountroot_hook(dev) c = cngetc(); if ((c == '\r') || (c == '\n')) { printf("\n"); - return; + break; } } } diff --git a/sys/arch/sparc/dev/fdreg.h b/sys/arch/sparc/dev/fdreg.h index 4166d58b0ba..bbe97ecb7c4 100644 --- a/sys/arch/sparc/dev/fdreg.h +++ b/sys/arch/sparc/dev/fdreg.h @@ -1,4 +1,5 @@ -/* $NetBSD: fdreg.h,v 1.5 1996/02/01 22:32:27 mycroft Exp $ */ +/* $OpenBSD: fdreg.h,v 1.3 1997/06/24 09:50:57 downsj Exp $ */ +/* $NetBSD: fdreg.h,v 1.6 1997/05/02 13:03:44 pk Exp $ */ /*- * Copyright (c) 1991 The Regents of the University of California. @@ -79,11 +80,13 @@ union fdreg { #define FDC_250KBPS 0x02 /* 250KBPS MFM drive transfer rate */ #define FDC_125KBPS 0x03 /* 125KBPS FM drive transfer rate */ -/* Digital Output Register bits */ -#define FDO_FDSEL 0x03 /* floppy device select */ -#define FDO_FRST 0x04 /* floppy controller reset */ +/* Digital Output Register bits (modified on suns) */ +#define FDO_DS 0x01 /* floppy device select (neg) */ +#define FDO_FRST 0x04 /* floppy controller reset (neg) */ #define FDO_FDMAEN 0x08 /* enable floppy DMA and Interrupt */ -#define FDO_MOEN(n) ((1 << n) * 0x10) /* motor enable */ +#define FDO_MOEN(n) ((1 << n) << 4) /* motor enable */ +#define FDO_DEN 0x40 /* Density select */ +#define FDO_EJ 0x80 /* Eject disk */ #define FDI_DCHG 0x80 /* diskette has been changed */ @@ -105,4 +108,4 @@ union fdreg { #define ST1_OVERRUN 0x10 - +#define NE7_SPECIFY_NODMA 0x01 diff --git a/sys/arch/sparc/dev/fdvar.h b/sys/arch/sparc/dev/fdvar.h index fdc0461e77a..c727ae374db 100644 --- a/sys/arch/sparc/dev/fdvar.h +++ b/sys/arch/sparc/dev/fdvar.h @@ -1,6 +1,6 @@ -/* $OpenBSD: fdvar.h,v 1.4 1996/08/11 23:16:36 downsj Exp $ */ +/* $OpenBSD: fdvar.h,v 1.5 1997/06/24 09:50:57 downsj Exp $ */ /* - * $NetBSD: fdvar.h,v 1.4 1996/02/01 22:32:29 mycroft Exp $ + * $NetBSD: fdvar.h,v 1.5 1996/12/08 23:40:34 pk Exp $ * * Copyright (c) 1995 Paul Kranenburg * All rights reserved. @@ -72,6 +72,7 @@ struct fdcio { #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 */ #define SUNOS_FDIOCEJECT _IO('f', 24) |