diff options
Diffstat (limited to 'sys/pc98/cbus/fdc.c')
-rw-r--r-- | sys/pc98/cbus/fdc.c | 2728 |
1 files changed, 0 insertions, 2728 deletions
diff --git a/sys/pc98/cbus/fdc.c b/sys/pc98/cbus/fdc.c deleted file mode 100644 index 90f230f5e871..000000000000 --- a/sys/pc98/cbus/fdc.c +++ /dev/null @@ -1,2728 +0,0 @@ -/* - * Copyright (c) 1990 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Don Ahn. - * - * Libretto PCMCIA floppy support by David Horwitt (dhorwitt@ucsd.edu) - * aided by the Linux floppy driver modifications from David Bateman - * (dbateman@eng.uts.edu.au). - * - * Copyright (c) 1993, 1994 by - * jc@irbs.UUCP (John Capo) - * vak@zebub.msk.su (Serge Vakulenko) - * ache@astral.msk.su (Andrew A. Chernov) - * - * Copyright (c) 1993, 1994, 1995 by - * joerg_wunsch@uriah.sax.de (Joerg Wunsch) - * dufault@hda.com (Peter Dufault) - * - * 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 University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. - * - * from: @(#)fd.c 7.4 (Berkeley) 5/25/91 - * $Id: fd.c,v 1.49 1999/01/16 11:40:02 kato Exp $ - * - */ - -#include "fd.h" -#include "opt_devfs.h" -#include "opt_fdc.h" - -#if NFDC > 0 - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/conf.h> -#include <sys/fcntl.h> -#include <machine/clock.h> -#include <machine/ioctl_fd.h> -#include <sys/disklabel.h> -#include <sys/buf.h> -#include <sys/devicestat.h> -#include <sys/malloc.h> -#include <sys/proc.h> -#include <sys/syslog.h> -#ifdef PC98 -#include <pc98/pc98/pc98.h> -#include <pc98/pc98/pc98_machdep.h> -#include <pc98/pc98/epsonio.h> -#include <i386/isa/isa_device.h> -#include <pc98/pc98/fdreg.h> -#else -#include <i386/isa/isa.h> -#include <i386/isa/isa_device.h> -#include <i386/isa/fdreg.h> -#include <i386/isa/rtc.h> -#endif -#include <i386/isa/fdc.h> -#include <machine/stdarg.h> -#ifdef DEVFS -#include <sys/devfsext.h> -#endif /* DEVFS */ - -/* misuse a flag to identify format operation */ -#define B_FORMAT B_XXX - -/* configuration flags */ -#define FDC_PRETEND_D0 (1 << 0) /* pretend drive 0 to be there */ -#ifdef FDC_YE -#define FDC_IS_PCMCIA (1 << 1) /* if successful probe, then it's - a PCMCIA device */ -#endif - -/* internally used only, not really from CMOS: */ -#define RTCFDT_144M_PRETENDED 0x1000 - -/* - * this biotab field doubles as a field for the physical unit number - * on the controller - */ -#define id_physid id_scsiid - -/* error returns for fd_cmd() */ -#define FD_FAILED -1 -#define FD_NOT_VALID -2 -#define FDC_ERRMAX 100 /* do not log more */ - -#ifdef PC98 -#define NUMTYPES 5 -#define NUMDENS NUMTYPES -#else -#define NUMTYPES 14 -#define NUMDENS (NUMTYPES - 6) -#endif - -/* These defines (-1) must match index for fd_types */ -#define F_TAPE_TYPE 0x020 /* bit for fd_types to indicate tape */ -#define NO_TYPE 0 /* must match NO_TYPE in ft.c */ -#ifdef PC98 -#define FDT_NONE 0 /* none present */ -#define FDT_12M 1 /* 1M/640K FDD */ -#define FDT_144M 2 /* 1.44M/1M/640K FDD */ - -#define FD_1200 1 -#define FD_1232 2 -#define FD_720 3 -#define FD_640 4 -#define FD_1440 5 -#else -#define FD_1720 1 -#define FD_1480 2 -#define FD_1440 3 -#define FD_1200 4 -#define FD_820 5 -#define FD_800 6 -#define FD_720 7 -#define FD_360 8 - -#define FD_1480in5_25 9 -#define FD_1440in5_25 10 -#define FD_820in5_25 11 -#define FD_800in5_25 12 -#define FD_720in5_25 13 -#define FD_360in5_25 14 -#endif - - -static struct fd_type fd_types[NUMTYPES] = -{ -#ifdef PC98 -{ 15,2,0xFF,0x1B,80,2400,1,0,2,0x54,1 }, /* 1.2 meg HD floppy */ -{ 8,3,0xFF,0x35,77,1232,1,0,2,0x74,1 }, /* 1.2 meg HD floppy 1024/sec */ -{ 9,2,0xFF,0x20,80,1440,1,1,2,0x50,1 }, /* 720k floppy in 1.2meg drive */ -{ 8,2,0xFF,0x2A,80,1280,1,1,2,0x50,1 }, /* 640k floppy in 1.2meg drive */ -{ 18,2,0xFF,0x1B,80,2880,1,2,2,0x54,1 }, /* 1.44 meg HD 3.5in floppy */ -#else -{ 21,2,0xFF,0x04,82,3444,1,FDC_500KBPS,2,0x0C,2 }, /* 1.72M in HD 3.5in */ -{ 18,2,0xFF,0x1B,82,2952,1,FDC_500KBPS,2,0x6C,1 }, /* 1.48M in HD 3.5in */ -{ 18,2,0xFF,0x1B,80,2880,1,FDC_500KBPS,2,0x6C,1 }, /* 1.44M in HD 3.5in */ -{ 15,2,0xFF,0x1B,80,2400,1,FDC_500KBPS,2,0x54,1 }, /* 1.2M in HD 5.25/3.5 */ -{ 10,2,0xFF,0x10,82,1640,1,FDC_250KBPS,2,0x2E,1 }, /* 820K in HD 3.5in */ -{ 10,2,0xFF,0x10,80,1600,1,FDC_250KBPS,2,0x2E,1 }, /* 800K in HD 3.5in */ -{ 9,2,0xFF,0x20,80,1440,1,FDC_250KBPS,2,0x50,1 }, /* 720K in HD 3.5in */ -{ 9,2,0xFF,0x2A,40, 720,1,FDC_250KBPS,2,0x50,1 }, /* 360K in DD 5.25in */ - -{ 18,2,0xFF,0x02,82,2952,1,FDC_500KBPS,2,0x02,2 }, /* 1.48M in HD 5.25in */ -{ 18,2,0xFF,0x02,80,2880,1,FDC_500KBPS,2,0x02,2 }, /* 1.44M in HD 5.25in */ -{ 10,2,0xFF,0x10,82,1640,1,FDC_300KBPS,2,0x2E,1 }, /* 820K in HD 5.25in */ -{ 10,2,0xFF,0x10,80,1600,1,FDC_300KBPS,2,0x2E,1 }, /* 800K in HD 5.25in */ -{ 9,2,0xFF,0x20,80,1440,1,FDC_300KBPS,2,0x50,1 }, /* 720K in HD 5.25in */ -{ 9,2,0xFF,0x23,40, 720,2,FDC_300KBPS,2,0x50,1 }, /* 360K in HD 5.25in */ -#endif -}; - -#ifdef PC98 -#define DRVS_PER_CTLR 4 /* 4 floppies */ -#else -#define DRVS_PER_CTLR 2 /* 2 floppies */ -#endif - -/***********************************************************************\ -* Per controller structure. * -\***********************************************************************/ -struct fdc_data fdc_data[NFDC]; - -/***********************************************************************\ -* Per drive structure. * -* N per controller (DRVS_PER_CTLR) * -\***********************************************************************/ -static struct fd_data { - struct fdc_data *fdc; /* pointer to controller structure */ - int fdsu; /* this units number on this controller */ - int type; /* Drive type (FD_1440...) */ - struct fd_type *ft; /* pointer to the type descriptor */ - int flags; -#define FD_OPEN 0x01 /* it's open */ -#define FD_ACTIVE 0x02 /* it's active */ -#define FD_MOTOR 0x04 /* motor should be on */ -#define FD_MOTOR_WAIT 0x08 /* motor coming up */ - int skip; - int hddrv; -#define FD_NO_TRACK -2 - int track; /* where we think the head is */ - int options; /* user configurable options, see ioctl_fd.h */ - struct callout_handle toffhandle; - struct callout_handle tohandle; - struct devstat device_stats; -#ifdef DEVFS - void *bdevs[1 + NUMDENS + MAXPARTITIONS]; - void *cdevs[1 + NUMDENS + MAXPARTITIONS]; -#endif -#ifdef PC98 - int pc98_trans; -#endif -} fd_data[NFD]; - -#ifdef EPSON_NRDISK -typedef unsigned int nrd_t; - -#define P_NRD_ADDRH 0xc24 -#define P_NRD_ADDRM 0xc22 -#define P_NRD_ADDRL 0xc20 -#define P_NRD_CHECK 0xc20 -#define P_NRD_DATA 0xc26 -#define P_NRD_LED 0xc36 -#define B_NRD_CHK 0x80 -#define B_NRD_LED 0x40 -#define A_NRD_INFO 0x2 -#define A_NRD_BASE 0x400 -#define NRD_STATUS 0x0 -#define NRD_ST0_HD 0x04 - -static fdu_t nrdu=-1; -static int nrdsec=0; -static nrd_t nrdblkn=0; -static nrd_t nrdaddr=0x0; - -#define nrd_check_ready() ({ \ - (epson_inb(P_NRD_CHECK) & B_NRD_CHK) ? 0 : 1; \ - }) -#define nrd_LED_on() epson_outb(P_NRD_LED, B_NRD_LED) -#define nrd_LED_off() epson_outb(P_NRD_LED, ~B_NRD_LED) -#define nrd_trac() ((int)(nrd_info(nrdaddr) & 0xff)) -#define nrd_head() ((int)((nrd_info(nrdaddr) >> 8) & 0xff)) -#define nrd_sec() ((int)(nrd_info(nrdaddr + 2) & 0xff)) -#define nrd_secsize() ((int)((nrd_info(A_NRD_INFO) >> 8) & 0xff)) -#define nrd_addrset(p) nrd_addr((nrd_t)((nrd_t)p+A_NRD_BASE)) - -static inline void -nrd_addr(addr) - nrd_t addr; -{ - epson_outb(P_NRD_ADDRH, (u_char)((addr >> 16) & 0x1f)); - epson_outb(P_NRD_ADDRM, (u_char)((addr >> 8) & 0xff)); - epson_outb(P_NRD_ADDRL, (u_char)(addr & 0xff)); -} - -static inline u_short -nrd_info(addr) - nrd_t addr; -{ - u_short tmp; - - nrd_addr(addr); - outb(0x43f, 0x42); - tmp = (short)inw(P_NRD_DATA); - outb(0x43f, 0x40); - return ((u_short)tmp); -} -#endif /* EPSON_NRDISK */ - -/***********************************************************************\ -* Throughout this file the following conventions will be used: * -* fd is a pointer to the fd_data struct for the drive in question * -* fdc is a pointer to the fdc_data struct for the controller * -* fdu is the floppy drive unit number * -* fdcu is the floppy controller unit number * -* fdsu is the floppy drive unit number on that controller. (sub-unit) * -\***********************************************************************/ - -#ifdef FDC_YE -#include "card.h" -static int yeattach(struct isa_device *); -#endif - -/* autoconfig functions */ -static int fdprobe(struct isa_device *); -static int fdattach(struct isa_device *); - -/* needed for ft driver, thus exported */ -int in_fdc(fdcu_t); -int out_fdc(fdcu_t, int); - -/* internal functions */ -static void set_motor(fdcu_t, int, int); -# define TURNON 1 -# define TURNOFF 0 -static timeout_t fd_turnoff; -static timeout_t fd_motor_on; -static void fd_turnon(fdu_t); -static void fdc_reset(fdc_p); -static int fd_in(fdcu_t, int *); -static void fdstart(fdcu_t); -static timeout_t fd_iotimeout; -static timeout_t fd_pseudointr; -static ointhand2_t fdintr; -static int fdstate(fdcu_t, fdc_p); -static int retrier(fdcu_t); -static int fdformat(dev_t, struct fd_formb *, struct proc *); - -static int enable_fifo(fdc_p fdc); - -static int fifo_threshold = 8; /* XXX: should be accessible via sysctl */ - - -#define DEVIDLE 0 -#define FINDWORK 1 -#define DOSEEK 2 -#define SEEKCOMPLETE 3 -#define IOCOMPLETE 4 -#define RECALCOMPLETE 5 -#define STARTRECAL 6 -#define RESETCTLR 7 -#define SEEKWAIT 8 -#define RECALWAIT 9 -#define MOTORWAIT 10 -#define IOTIMEDOUT 11 -#define RESETCOMPLETE 12 -#ifdef FDC_YE -#define PIOREAD 13 -#endif - -#ifdef FDC_DEBUG -static char const * const fdstates[] = -{ -"DEVIDLE", -"FINDWORK", -"DOSEEK", -"SEEKCOMPLETE", -"IOCOMPLETE", -"RECALCOMPLETE", -"STARTRECAL", -"RESETCTLR", -"SEEKWAIT", -"RECALWAIT", -"MOTORWAIT", -"IOTIMEDOUT", -"RESETCOMPLETE", -#ifdef FDC_YE -"PIOREAD", -#endif -}; - -/* CAUTION: fd_debug causes huge amounts of logging output */ -static int volatile fd_debug = 0; -#define TRACE0(arg) if(fd_debug) printf(arg) -#define TRACE1(arg1, arg2) if(fd_debug) printf(arg1, arg2) -#else /* FDC_DEBUG */ -#define TRACE0(arg) -#define TRACE1(arg1, arg2) -#endif /* FDC_DEBUG */ - -#ifdef FDC_YE -#if NCARD > 0 -#include <sys/select.h> -#include <sys/module.h> -#include <pccard/cardinfo.h> -#include <pccard/driver.h> -#include <pccard/slot.h> - -/* - * PC-Card (PCMCIA) specific code. - */ -static int yeinit(struct pccard_devinfo *); /* init device */ -static void yeunload(struct pccard_devinfo *); /* Disable driver */ -static int yeintr(struct pccard_devinfo *); /* Interrupt handler */ - -PCCARD_MODULE(fdc, yeinit, yeunload, yeintr, 0, bio_imask); - -/* - * this is the secret PIO data port (offset from base) - */ -#define FDC_YE_DATAPORT 6 - -/* - * Initialize the device - called from Slot manager. - */ -static int yeinit(struct pccard_devinfo *devi) -{ - fdc_p fdc = &fdc_data[devi->isahd.id_unit]; - - /* validate unit number. */ - if (devi->isahd.id_unit >= NFDC) - return(ENODEV); - fdc->baseport = devi->isahd.id_iobase; - /* - * reset controller - */ - outb(fdc->baseport+FDOUT, 0); - DELAY(100); - outb(fdc->baseport+FDOUT, FDO_FRST); - - /* - * wire into system - */ - if (yeattach(&devi->isahd) == 0) - return(ENXIO); - - return(0); -} - -/* - * yeunload - unload the driver and clear the table. - * XXX TODO: - * This is usually called when the card is ejected, but - * can be caused by a modunload of a controller driver. - * The idea is to reset the driver's view of the device - * and ensure that any driver entry points such as - * read and write do not hang. - */ -static void yeunload(struct pccard_devinfo *devi) -{ - if (fd_data[devi->isahd.id_unit].type == NO_TYPE) - return; - - /* - * this prevents Fdopen() and fdstrategy() from attempting - * to access unloaded controller - */ - fd_data[devi->isahd.id_unit].type = NO_TYPE; - - printf("fdc%d: unload\n", devi->isahd.id_unit); -} - -/* - * yeintr - Shared interrupt called from - * front end of PC-Card handler. - */ -static int yeintr(struct pccard_devinfo *devi) -{ - fdintr((fdcu_t)devi->isahd.id_unit); - return(1); -} -#endif /* NCARD > 0 */ -#endif /* FDC_YE */ - - -/* autoconfig structure */ - -struct isa_driver fdcdriver = { - fdprobe, fdattach, "fdc", -}; - -static d_open_t Fdopen; /* NOTE, not fdopen */ -static d_read_t fdread; -static d_write_t fdwrite; -static d_close_t fdclose; -static d_ioctl_t fdioctl; -static d_strategy_t fdstrategy; - -/* even if SLICE defined, these are needed for the ft support. */ -#define CDEV_MAJOR 9 -#define BDEV_MAJOR 2 - - -static struct cdevsw fd_cdevsw = { - Fdopen, fdclose, fdread, fdwrite, - fdioctl, nostop, nullreset, nodevtotty, - seltrue, nommap, fdstrategy, "fd", - NULL, -1, nodump, nopsize, - D_DISK, 0, -1 }; - - -static struct isa_device *fdcdevs[NFDC]; - - -static int -fdc_err(fdcu_t fdcu, const char *s) -{ - fdc_data[fdcu].fdc_errs++; - if(s) { - if(fdc_data[fdcu].fdc_errs < FDC_ERRMAX) - printf("fdc%d: %s", fdcu, s); - else if(fdc_data[fdcu].fdc_errs == FDC_ERRMAX) - printf("fdc%d: too many errors, not logging any more\n", - fdcu); - } - - return FD_FAILED; -} - -/* - * fd_cmd: Send a command to the chip. Takes a varargs with this structure: - * Unit number, - * # of output bytes, output bytes as ints ..., - * # of input bytes, input bytes as ints ... - */ - -static int -fd_cmd(fdcu_t fdcu, int n_out, ...) -{ - u_char cmd; - int n_in; - int n; - va_list ap; - - va_start(ap, n_out); - cmd = (u_char)(va_arg(ap, int)); - va_end(ap); - va_start(ap, n_out); - for (n = 0; n < n_out; n++) - { - if (out_fdc(fdcu, va_arg(ap, int)) < 0) - { - char msg[50]; - snprintf(msg, sizeof(msg), - "cmd %x failed at out byte %d of %d\n", - cmd, n + 1, n_out); - return fdc_err(fdcu, msg); - } - } - n_in = va_arg(ap, int); - for (n = 0; n < n_in; n++) - { - int *ptr = va_arg(ap, int *); - if (fd_in(fdcu, ptr) < 0) - { - char msg[50]; - snprintf(msg, sizeof(msg), - "cmd %02x failed at in byte %d of %d\n", - cmd, n + 1, n_in); - return fdc_err(fdcu, msg); - } - } - - return 0; -} - -static int -enable_fifo(fdc_p fdc) -{ - int i, j; - - if ((fdc->flags & FDC_HAS_FIFO) == 0) { - - /* - * XXX: - * Cannot use fd_cmd the normal way here, since - * this might be an invalid command. Thus we send the - * first byte, and check for an early turn of data directon. - */ - - if (out_fdc(fdc->fdcu, I8207X_CONFIGURE) < 0) - return fdc_err(fdc->fdcu, "Enable FIFO failed\n"); - - /* If command is invalid, return */ - j = 100000; - while ((i = inb(fdc->baseport + FDSTS) & (NE7_DIO | NE7_RQM)) - != NE7_RQM && j-- > 0) - if (i == (NE7_DIO | NE7_RQM)) { - fdc_reset(fdc); - return FD_FAILED; - } - if (j<0 || - fd_cmd(fdc->fdcu, 3, - 0, (fifo_threshold - 1) & 0xf, 0, 0) < 0) { - fdc_reset(fdc); - return fdc_err(fdc->fdcu, "Enable FIFO failed\n"); - } - fdc->flags |= FDC_HAS_FIFO; - return 0; - } - if (fd_cmd(fdc->fdcu, 4, - I8207X_CONFIGURE, 0, (fifo_threshold - 1) & 0xf, 0, 0) < 0) - return fdc_err(fdc->fdcu, "Re-enable FIFO failed\n"); - return 0; -} - -static int -fd_sense_drive_status(fdc_p fdc, int *st3p) -{ - int st3; - - if (fd_cmd(fdc->fdcu, 2, NE7CMD_SENSED, fdc->fdu, 1, &st3)) - { - return fdc_err(fdc->fdcu, "Sense Drive Status failed\n"); - } - if (st3p) - *st3p = st3; - - return 0; -} - -static int -fd_sense_int(fdc_p fdc, int *st0p, int *cylp) -{ - int st0, cyl; - -#ifdef EPSON_NRDISK - if (fdc->fdu == nrdu) { - if (fdc->fd->track >= 0) nrdaddr = (fdc->fd->track + 1) * 8; - else nrdaddr = 0x0; - *st0p = nrd_head() ? NRD_ST0_HD : NRD_STATUS; - *cylp = nrd_trac(); - } - else { -#endif /* EPSON_NRDISK */ - int ret = fd_cmd(fdc->fdcu, 1, NE7CMD_SENSEI, 1, &st0); - - if (ret) - { - (void)fdc_err(fdc->fdcu, - "sense intr err reading stat reg 0\n"); - return ret; - } - - if (st0p) - *st0p = st0; - - if ((st0 & NE7_ST0_IC) == NE7_ST0_IC_IV) - { - /* - * There doesn't seem to have been an interrupt. - */ - return FD_NOT_VALID; - } - - if (fd_in(fdc->fdcu, &cyl) < 0) - { - return fdc_err(fdc->fdcu, "can't get cyl num\n"); - } - - if (cylp) - *cylp = cyl; - -#ifdef EPSON_NRDISK - } -#endif /* EPSON_NRDISK */ - return 0; -} - - -static int -fd_read_status(fdc_p fdc, int fdsu) -{ - int i, ret; - - for (i = 0; i < 7; i++) - { - /* - * XXX types are poorly chosen. Only bytes can by read - * from the hardware, but fdc->status[] wants u_ints and - * fd_in() gives ints. - */ - int status; - -#ifdef EPSON_NRDISK - if (fdc->fdu == nrdu) { - switch (i) { - case 0: fdc->status[i] = nrd_head() - ? NRD_ST0_HD : NRD_STATUS; break; - case 1: fdc->status[i] = NRD_STATUS; break; - case 2: fdc->status[i] = NRD_STATUS; break; - case 3: fdc->status[i] = nrd_trac(); break; - case 4: fdc->status[i] = nrd_head(); break; - case 5: fdc->status[i] = nrdsec; break; - case 6: fdc->status[i] = nrd_secsize(); break; - } - ret = 0; - } - else { -#endif /* EPSON_NRDISK */ - ret = fd_in(fdc->fdcu, &status); - fdc->status[i] = status; - if (ret != 0) - break; -#ifdef EPSON_NRDISK - } -#endif /* EPSON_NRDISK */ - } - - if (ret == 0) - fdc->flags |= FDC_STAT_VALID; - else - fdc->flags &= ~FDC_STAT_VALID; - - return ret; -} - -/****************************************************************************/ -/* autoconfiguration stuff */ -/****************************************************************************/ -#ifdef PC98 -static int pc98_trans = 0; /* 0 : HD , 1 : DD , 2 : 1.44 */ -static int pc98_trans_prev = 0; - -static void set_density(fdcu_t, fdu_t); -static int pc98_fd_check_ready(fdu_t); - -static void set_density(fdcu, fdu) - fdcu_t fdcu; - fdu_t fdu; -{ - /* always motor on */ - outb(IO_FDPORT, - (pc98_trans != 1 ? FDP_FDDEXC : 0) | FDP_PORTEXC); - DELAY(100); - outb(fdc_data[fdcu].baseport + FDOUT, FDO_RST | FDO_DMAE); - /* in the case of note W, always inhibit 100ms timer */ -} - -static int pc98_fd_check_ready(fdu) - fdu_t fdu; -{ - fd_p fd = fd_data + fdu; - fdcu_t fdcu = fd->fdc->fdcu; - int retry = 0; - -#ifdef EPSON_NRDISK - if (fdu == nrdu) { - if (nrd_check_ready()) return 0; - else return -1; - } -#endif - while (retry++ < 30000) { - set_motor(fdcu, fd->fdsu, TURNON); - out_fdc(fdcu, NE7CMD_SENSED); /* Sense Drive Status */ - DELAY(100); - out_fdc(fdcu, fdu); /* Drive number */ - DELAY(100); - if ((in_fdc(fdcu) & NE7_ST3_RD)){ - outb(fdc_data[fdcu].baseport + FDOUT, - FDO_DMAE | FDO_MTON); - DELAY(10); - return 0; - } - } - return -1; -} -#endif - - -/* - * probe for existance of controller - */ -static int -fdprobe(struct isa_device *dev) -{ - fdcu_t fdcu = dev->id_unit; - if(fdc_data[fdcu].flags & FDC_ATTACHED) - { - printf("fdc%d: unit used multiple times\n", fdcu); - return 0; - } - - fdcdevs[fdcu] = dev; - fdc_data[fdcu].baseport = dev->id_iobase; - -#ifndef PC98 - /* First - lets reset the floppy controller */ - outb(dev->id_iobase+FDOUT, 0); - DELAY(100); - outb(dev->id_iobase+FDOUT, FDO_FRST); -#endif - - /* see if it can handle a command */ -#ifdef PC98 - if (fd_cmd(fdcu, - 3, NE7CMD_SPECIFY, NE7_SPEC_1(4, 240), NE7_SPEC_2(2, 0), - 0)) -#else - if (fd_cmd(fdcu, - 3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0), - 0)) -#endif - { - return(0); - } -#ifdef FDC_YE - /* - * don't succeed on probe; wait - * for PCCARD subsystem to do it - */ - if (dev->id_flags & FDC_IS_PCMCIA) - return(0); -#endif - return (IO_FDCSIZE); -} - -/* - * wire controller into system, look for floppy units - */ -static int -fdattach(struct isa_device *dev) -{ - unsigned fdt; - fdu_t fdu; - fdcu_t fdcu = dev->id_unit; - fdc_p fdc = fdc_data + fdcu; - fd_p fd; - int fdsu, st0, st3, i; - struct isa_device *fdup; - int ic_type = 0; -#ifdef DEVFS - int mynor; - int typemynor; - int typesize; -#endif - - dev->id_ointr = fdintr; - fdc->fdcu = fdcu; - fdc->flags |= FDC_ATTACHED; -#ifdef PC98 - fdc->dmachan = 2; - if (fdc->dmachan != dev->id_drq) { - dev->id_drq = fdc->dmachan; - printf(" [dma is changed to #%d]", fdc->dmachan); - } - /* Acquire the DMA channel forever, The driver will do the rest */ - isa_dma_acquire(fdc->dmachan); - isa_dmainit(fdc->dmachan, 128 << 3 /* XXX max secsize */); - fdc->state = DEVIDLE; - fdc_reset(fdc); -#else - fdc->dmachan = dev->id_drq; - /* Acquire the DMA channel forever, The driver will do the rest */ - isa_dma_acquire(fdc->dmachan); - isa_dmainit(fdc->dmachan, 128 << 3 /* XXX max secsize */); - fdc->state = DEVIDLE; - /* reset controller, turn motor off, clear fdout mirror reg */ - outb(fdc->baseport + FDOUT, ((fdc->fdout = 0))); -#endif - bufq_init(&fdc->head); - - /* check for each floppy drive */ - for (fdup = isa_biotab_fdc; fdup->id_driver != 0; fdup++) { - if (fdup->id_iobase != dev->id_iobase) - continue; - fdu = fdup->id_unit; - fd = &fd_data[fdu]; - if (fdu >= (NFD)) - continue; - fdsu = fdup->id_physid; - /* look up what bios thinks we have */ - switch (fdu) { -#ifdef PC98 - case 0: case 1: case 2: case 3: - if ((PC98_SYSTEM_PARAMETER(0x5ae) >> fdu) & 0x01) - fdt = FDT_144M; -#ifdef EPSON_NRDISK - else if ((PC98_SYSTEM_PARAMETER(0x55c) >> fdu) & 0x01) { - fdt = FDT_12M; - switch (epson_machine_id) { - case 0x20: case 0x27: - if ((PC98_SYSTEM_PARAMETER(0x488) >> fdu) & 0x01) { - if (nrd_check_ready()) { - nrd_LED_on(); - nrdu = fdu; - } - else fdt = FDT_NONE; - } - } - } -#else /* !EPSON_NRDISK */ - else if ((PC98_SYSTEM_PARAMETER(0x55c) >> fdu) & 0x01) { - fdt = FDT_12M; - switch (epson_machine_id) { - case 0x20: case 0x27: - if ((PC98_SYSTEM_PARAMETER(0x488) >> fdu) & 0x01) - fdt = FDT_NONE; - } - } -#endif /* EPSON_NRDISK */ - else fdt = FDT_NONE; - break; - default: - fdt = FDT_NONE; - break; -#else - case 0: if (dev->id_flags & FDC_PRETEND_D0) - fdt = RTCFDT_144M | RTCFDT_144M_PRETENDED; - else - fdt = (rtcin(RTC_FDISKETTE) & 0xf0); - break; - case 1: fdt = ((rtcin(RTC_FDISKETTE) << 4) & 0xf0); - break; - default: fdt = RTCFDT_NONE; - break; -#endif - } - /* is there a unit? */ -#ifdef PC98 - if ((fdt == FDT_NONE) -#else - if ((fdt == RTCFDT_NONE) -#endif - ) { -#ifdef PC98 - fd->fdc = fdc; -#endif - fd->type = NO_TYPE; - continue; - } - -#ifndef PC98 - /* select it */ - set_motor(fdcu, fdsu, TURNON); - DELAY(1000000); /* 1 sec */ - - if (ic_type == 0 && - fd_cmd(fdcu, 1, NE7CMD_VERSION, 1, &ic_type) == 0) - { -#ifdef FDC_PRINT_BOGUS_CHIPTYPE - printf("fdc%d: ", fdcu); -#endif - ic_type = (u_char)ic_type; - switch( ic_type ) { - case 0x80: -#ifdef FDC_PRINT_BOGUS_CHIPTYPE - printf("NEC 765\n"); -#endif - fdc->fdct = FDC_NE765; - break; - case 0x81: -#ifdef FDC_PRINT_BOGUS_CHIPTYPE - printf("Intel 82077\n"); -#endif - fdc->fdct = FDC_I82077; - break; - case 0x90: -#ifdef FDC_PRINT_BOGUS_CHIPTYPE - printf("NEC 72065B\n"); -#endif - fdc->fdct = FDC_NE72065; - break; - default: -#ifdef FDC_PRINT_BOGUS_CHIPTYPE - printf("unknown IC type %02x\n", ic_type); -#endif - fdc->fdct = FDC_UNKNOWN; - break; - } - if (fdc->fdct != FDC_NE765 && - fdc->fdct != FDC_UNKNOWN && - enable_fifo(fdc) == 0) { - printf("fdc%d: FIFO enabled", fdcu); - printf(", %d bytes threshold\n", - fifo_threshold); - } - } - if ((fd_cmd(fdcu, 2, NE7CMD_SENSED, fdsu, 1, &st3) == 0) && - (st3 & NE7_ST3_T0)) { - /* if at track 0, first seek inwards */ - /* seek some steps: */ - (void)fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0); - DELAY(300000); /* ...wait a moment... */ - (void)fd_sense_int(fdc, 0, 0); /* make ctrlr happy */ - } - - /* If we're at track 0 first seek inwards. */ - if ((fd_sense_drive_status(fdc, &st3) == 0) && - (st3 & NE7_ST3_T0)) { - /* Seek some steps... */ - if (fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) { - /* ...wait a moment... */ - DELAY(300000); - /* make ctrlr happy: */ - (void)fd_sense_int(fdc, 0, 0); - } - } - - for(i = 0; i < 2; i++) { - /* - * we must recalibrate twice, just in case the - * heads have been beyond cylinder 76, since most - * FDCs still barf when attempting to recalibrate - * more than 77 steps - */ - /* go back to 0: */ - if (fd_cmd(fdcu, 2, NE7CMD_RECAL, fdsu, 0) == 0) { - /* a second being enough for full stroke seek*/ - DELAY(i == 0? 1000000: 300000); - - /* anything responding? */ - if (fd_sense_int(fdc, &st0, 0) == 0 && - (st0 & NE7_ST0_EC) == 0) - break; /* already probed succesfully */ - } - } - - set_motor(fdcu, fdsu, TURNOFF); - - if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */ - continue; -#endif - - fd->track = FD_NO_TRACK; - fd->fdc = fdc; - fd->fdsu = fdsu; - fd->options = 0; - callout_handle_init(&fd->toffhandle); - callout_handle_init(&fd->tohandle); - printf("fd%d: ", fdu); - - switch (fdt) { -#ifdef PC98 - case FDT_12M: -#ifdef EPSON_NRDISK - if (fdu == nrdu) { - printf("EPSON RAM DRIVE\n"); - nrd_LED_off(); - } - else printf("1M/640M FDD\n"); -#else /* !EPSON_NRDISK */ - printf("1M/640K FDD\n"); -#endif /* EPSON_NRDISK */ - fd->type = FD_1200; - fd->pc98_trans = 0; - break; - case FDT_144M: - printf("1.44M FDD\n"); - fd->type = FD_1200; - fd->pc98_trans = 0; - outb(0x4be, (fdu << 5) | 0x10); - break; -#else - case RTCFDT_12M: - printf("1.2MB 5.25in\n"); - fd->type = FD_1200; - break; - case RTCFDT_144M | RTCFDT_144M_PRETENDED: - printf("config-pretended "); - fdt = RTCFDT_144M; - /* fallthrough */ - case RTCFDT_144M: - printf("1.44MB 3.5in\n"); - fd->type = FD_1440; - break; - case RTCFDT_288M: - case RTCFDT_288M_1: - printf("2.88MB 3.5in - 1.44MB mode\n"); - fd->type = FD_1440; - break; - case RTCFDT_360K: - printf("360KB 5.25in\n"); - fd->type = FD_360; - break; - case RTCFDT_720K: - printf("720KB 3.5in\n"); - fd->type = FD_720; - break; -#endif - default: - printf("unknown\n"); - fd->type = NO_TYPE; - continue; - } -#ifdef DEVFS - mynor = fdu << 6; - fd->bdevs[0] = devfs_add_devswf(&fd_cdevsw, mynor, DV_BLK, - UID_ROOT, GID_OPERATOR, 0640, - "fd%d", fdu); - fd->cdevs[0] = devfs_add_devswf(&fd_cdevsw, mynor, DV_CHR, - UID_ROOT, GID_OPERATOR, 0640, - "rfd%d", fdu); - for (i = 1; i < 1 + NUMDENS; i++) { - /* - * XXX this and the lookup in Fdopen() should be - * data driven. - */ -#ifdef PC98 - switch (fdt) { - case FDT_12M: - if (i != FD_1200 && i != FD_1232 - && i != FD_720 && i != FD_640) - continue; - break; - case FDT_144M: - if (i != FD_1200 && i != FD_1232 - && i != FD_720 && i != FD_640 - && i != FD_1440) - continue; - break; - } -#else - switch (fd->type) { - case FD_360: - if (i != FD_360) - continue; - break; - case FD_720: - if (i != FD_720 && i != FD_800 && i != FD_820) - continue; - break; - case FD_1200: - if (i != FD_360 && i != FD_720 && i != FD_800 - && i != FD_820 && i != FD_1200 - && i != FD_1440 && i != FD_1480) - continue; - break; - case FD_1440: - if (i != FD_720 && i != FD_800 && i != FD_820 - && i != FD_1200 && i != FD_1440 - && i != FD_1480 && i != FD_1720) - continue; - break; - } -#endif -#ifdef PC98 - if (i == FD_1232) - typesize = fd_types[i - 1].size; - else - typesize = fd_types[i - 1].size / 2; -#else - typesize = fd_types[i - 1].size / 2; - /* - * XXX all these conversions give bloated code and - * confusing names. - */ - if (typesize == 1476) - typesize = 1480; - if (typesize == 1722) - typesize = 1720; -#endif - typemynor = mynor | i; - fd->bdevs[i] = - devfs_add_devswf(&fd_cdevsw, typemynor, DV_BLK, - UID_ROOT, GID_OPERATOR, 0640, - "fd%d.%d", fdu, typesize); - fd->cdevs[i] = - devfs_add_devswf(&fd_cdevsw, typemynor, DV_CHR, - UID_ROOT, GID_OPERATOR, 0640, - "rfd%d.%d", fdu, typesize); - } - - for (i = 0; i < MAXPARTITIONS; i++) { - fd->bdevs[1 + NUMDENS + i] = devfs_makelink(fd->bdevs[0], - "fd%d%c", fdu, 'a' + i); - fd->cdevs[1 + NUMDENS + i] = - devfs_makelink(fd->cdevs[0], - "rfd%d%c", fdu, 'a' + i); - } -#endif /* DEVFS */ - /* - * Export the drive to the devstat interface. - */ - devstat_add_entry(&fd->device_stats, "fd", - fdu, 512, - DEVSTAT_NO_ORDERED_TAGS, - DEVSTAT_TYPE_FLOPPY | DEVSTAT_TYPE_IF_OTHER); - - } - - return (1); -} - - - -#ifdef FDC_YE -/* - * this is a subset of fdattach() optimized for the Y-E Data - * PCMCIA floppy drive. - */ -static int yeattach(struct isa_device *dev) -{ - fdcu_t fdcu = dev->id_unit; - fdc_p fdc = fdc_data + fdcu; - fdsu_t fdsu = 0; /* assume 1 drive per YE controller */ - fdu_t fdu; - fd_p fd; - int st0, st3, i; -#ifdef DEVFS - int mynor; - int typemynor; - int typesize; -#endif - fdc->fdcu = fdcu; - /* - * the FDC_PCMCIA flag is used to to indicate special PIO is used - * instead of DMA - */ - fdc->flags = FDC_ATTACHED|FDC_PCMCIA; - fdc->state = DEVIDLE; - /* reset controller, turn motor off, clear fdout mirror reg */ - outb(fdc->baseport + FDOUT, ((fdc->fdout = 0))); - bufq_init(&fdc->head); - /* - * assume 2 drives/ "normal" controller - */ - fdu = fdcu * 2; - if (fdu >= NFD) { - printf("fdu %d >= NFD\n",fdu); - return(0); - }; - fd = &fd_data[fdu]; - - set_motor(fdcu, fdsu, TURNON); - DELAY(1000000); /* 1 sec */ - fdc->fdct = FDC_NE765; - - if ((fd_cmd(fdcu, 2, NE7CMD_SENSED, fdsu, 1, &st3) == 0) && - (st3 & NE7_ST3_T0)) { - /* if at track 0, first seek inwards */ - /* seek some steps: */ - (void)fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0); - DELAY(300000); /* ...wait a moment... */ - (void)fd_sense_int(fdc, 0, 0); /* make ctrlr happy */ - } - - /* If we're at track 0 first seek inwards. */ - if ((fd_sense_drive_status(fdc, &st3) == 0) && (st3 & NE7_ST3_T0)) { - /* Seek some steps... */ - if (fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) { - /* ...wait a moment... */ - DELAY(300000); - /* make ctrlr happy: */ - (void)fd_sense_int(fdc, 0, 0); - } - } - - for(i = 0; i < 2; i++) { - /* - * we must recalibrate twice, just in case the - * heads have been beyond cylinder 76, since most - * FDCs still barf when attempting to recalibrate - * more than 77 steps - */ - /* go back to 0: */ - if (fd_cmd(fdcu, 2, NE7CMD_RECAL, fdsu, 0) == 0) { - /* a second being enough for full stroke seek*/ - DELAY(i == 0? 1000000: 300000); - - /* anything responding? */ - if (fd_sense_int(fdc, &st0, 0) == 0 && - (st0 & NE7_ST0_EC) == 0) - break; /* already probed succesfully */ - } - } - - set_motor(fdcu, fdsu, TURNOFF); - - if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */ - return(0); - - fd->track = FD_NO_TRACK; - fd->fdc = fdc; - fd->fdsu = fdsu; - fd->options = 0; - printf("fdc%d: 1.44MB 3.5in PCMCIA\n", fdcu); - fd->type = FD_1440; - -#ifdef DEVFS - mynor = fdcu << 6; - fd->bdevs[0] = devfs_add_devswf(&fd_cdevsw, mynor, DV_BLK, - UID_ROOT, GID_OPERATOR, 0640, - "fd%d", fdu); - fd->cdevs[0] = devfs_add_devswf(&fd_cdevsw, mynor, DV_CHR, - UID_ROOT, GID_OPERATOR, 0640, - "rfd%d", fdu); - /* - * XXX this and the lookup in Fdopen() should be - * data driven. - */ - typemynor = mynor | FD_1440; - typesize = fd_types[FD_1440 - 1].size / 2; - /* - * XXX all these conversions give bloated code and - * confusing names. - */ - if (typesize == 1476) - typesize = 1480; - if (typesize == 1722) - typesize = 1720; - fd->bdevs[FD_1440] = devfs_add_devswf(&fd_cdevsw, typemynor, - DV_BLK, UID_ROOT, GID_OPERATOR, - 0640, "fd%d.%d", fdu, typesize); - fd->cdevs[FD_1440] = devfs_add_devswf(&fd_cdevsw, typemynor, - DV_CHR, UID_ROOT, GID_OPERATOR, - 0640,"rfd%d.%d", fdu, typesize); - for (i = 0; i < MAXPARTITIONS; i++) { - fd->bdevs[1 + NUMDENS + i] = devfs_makelink(fd->bdevs[0], - "fd%d%c", fdu, 'a' + i); - fd->cdevs[1 + NUMDENS + i] = devfs_makelink(fd->cdevs[0], - "rfd%d%c", fdu, 'a' + i); - } -#endif /* DEVFS */ - return (1); -} -#endif - -/****************************************************************************/ -/* motor control stuff */ -/* remember to not deselect the drive we're working on */ -/****************************************************************************/ -static void -set_motor(fdcu_t fdcu, int fdsu, int turnon) -{ - int fdout = fdc_data[fdcu].fdout; - int needspecify = 0; - -#ifdef PC98 - outb(IO_FDPORT, (pc98_trans != 1 ? FDP_FDDEXC : 0)|FDP_PORTEXC); - DELAY(10); - fdout = FDO_DMAE|FDO_MTON; -#else - if(turnon) { - fdout &= ~FDO_FDSEL; - fdout |= (FDO_MOEN0 << fdsu) + fdsu; - } else - fdout &= ~(FDO_MOEN0 << fdsu); - - if(!turnon - && (fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0) - /* gonna turn off the last drive, put FDC to bed */ - fdout &= ~ (FDO_FRST|FDO_FDMAEN); - else { - /* make sure controller is selected and specified */ - if((fdout & (FDO_FRST|FDO_FDMAEN)) == 0) - needspecify = 1; - fdout |= (FDO_FRST|FDO_FDMAEN); - } -#endif - - outb(fdc_data[fdcu].baseport+FDOUT, fdout); - DELAY(10); - fdc_data[fdcu].fdout = fdout; - TRACE1("[0x%x->FDOUT]", fdout); - - if(needspecify) { - /* - * XXX - * special case: since we have just woken up the FDC - * from its sleep, we silently assume the command will - * be accepted, and do not test for a timeout - */ -#ifdef PC98 - (void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY, - NE7_SPEC_1(4, 240), NE7_SPEC_2(2, 0), - 0); -#else - (void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY, - NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0), - 0); -#endif - if (fdc_data[fdcu].flags & FDC_HAS_FIFO) - (void) enable_fifo(&fdc_data[fdcu]); - - } -} - -static void -fd_turnoff(void *arg1) -{ - fdu_t fdu = (fdu_t)arg1; - int s; - fd_p fd = fd_data + fdu; - - TRACE1("[fd%d: turnoff]", fdu); - - /* - * Don't turn off the motor yet if the drive is active. - * XXX shouldn't even schedule turnoff until drive is inactive - * and nothing is queued on it. - */ - if (fd->fdc->state != DEVIDLE && fd->fdc->fdu == fdu) { - fd->toffhandle = timeout(fd_turnoff, arg1, 4 * hz); - return; - } - - s = splbio(); - fd->flags &= ~FD_MOTOR; - set_motor(fd->fdc->fdcu, fd->fdsu, TURNOFF); - splx(s); -} - -static void -fd_motor_on(void *arg1) -{ - fdu_t fdu = (fdu_t)arg1; - int s; - - fd_p fd = fd_data + fdu; - s = splbio(); - fd->flags &= ~FD_MOTOR_WAIT; - if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT)) - { - fdintr(fd->fdc->fdcu); - } - splx(s); -} - -static void -fd_turnon(fdu_t fdu) -{ - fd_p fd = fd_data + fdu; - if(!(fd->flags & FD_MOTOR)) - { - fd->flags |= (FD_MOTOR + FD_MOTOR_WAIT); - set_motor(fd->fdc->fdcu, fd->fdsu, TURNON); - timeout(fd_motor_on, (caddr_t)fdu, hz); /* in 1 sec its ok */ - } -} - -static void -fdc_reset(fdc_p fdc) -{ - fdcu_t fdcu = fdc->fdcu; - - /* Try a reset, keep motor on */ -#ifdef PC98 - set_density(fdcu, 0); - if (pc98_machine_type & M_EPSON_PC98) - outb(fdc->baseport + FDOUT, 0xe8); - else - outb(fdc->baseport + FDOUT, 0xd8); - DELAY(200); - outb(fdc->baseport + FDOUT, 0x18); - DELAY(10); -#else - outb(fdc->baseport + FDOUT, fdc->fdout & ~(FDO_FRST|FDO_FDMAEN)); - TRACE1("[0x%x->FDOUT]", fdc->fdout & ~(FDO_FRST|FDO_FDMAEN)); - DELAY(100); - /* enable FDC, but defer interrupts a moment */ - outb(fdc->baseport + FDOUT, fdc->fdout & ~FDO_FDMAEN); - TRACE1("[0x%x->FDOUT]", fdc->fdout & ~FDO_FDMAEN); - DELAY(100); - outb(fdc->baseport + FDOUT, fdc->fdout); - TRACE1("[0x%x->FDOUT]", fdc->fdout); -#endif - - /* XXX after a reset, silently believe the FDC will accept commands */ -#ifdef PC98 - (void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY, - NE7_SPEC_1(4, 240), NE7_SPEC_2(2, 0), - 0); -#else - (void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY, - NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0), - 0); -#endif - if (fdc->flags & FDC_HAS_FIFO) - (void) enable_fifo(fdc); -} - -/****************************************************************************/ -/* fdc in/out */ -/****************************************************************************/ -int -in_fdc(fdcu_t fdcu) -{ - int baseport = fdc_data[fdcu].baseport; - int i, j = 100000; - while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM)) - != (NE7_DIO|NE7_RQM) && j-- > 0) - if (i == NE7_RQM) - return fdc_err(fdcu, "ready for output in input\n"); - if (j <= 0) - return fdc_err(fdcu, bootverbose? "input ready timeout\n": 0); -#ifdef FDC_DEBUG - i = inb(baseport+FDDATA); - TRACE1("[FDDATA->0x%x]", (unsigned char)i); - return(i); -#else /* !FDC_DEBUG */ - return inb(baseport+FDDATA); -#endif /* FDC_DEBUG */ -} - -/* - * fd_in: Like in_fdc, but allows you to see if it worked. - */ -static int -fd_in(fdcu_t fdcu, int *ptr) -{ - int baseport = fdc_data[fdcu].baseport; - int i, j = 100000; - while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM)) - != (NE7_DIO|NE7_RQM) && j-- > 0) - if (i == NE7_RQM) - return fdc_err(fdcu, "ready for output in input\n"); - if (j <= 0) - return fdc_err(fdcu, bootverbose? "input ready timeout\n": 0); -#ifdef FDC_DEBUG - i = inb(baseport+FDDATA); - TRACE1("[FDDATA->0x%x]", (unsigned char)i); - *ptr = i; - return 0; -#else /* !FDC_DEBUG */ - i = inb(baseport+FDDATA); - if (ptr) - *ptr = i; - return 0; -#endif /* FDC_DEBUG */ -} - -int -out_fdc(fdcu_t fdcu, int x) -{ - int baseport = fdc_data[fdcu].baseport; - int i; - - /* Check that the direction bit is set */ - i = 100000; - while ((inb(baseport+FDSTS) & NE7_DIO) && i-- > 0); - if (i <= 0) return fdc_err(fdcu, "direction bit not set\n"); - - /* Check that the floppy controller is ready for a command */ - i = 100000; - while ((inb(baseport+FDSTS) & NE7_RQM) == 0 && i-- > 0); - if (i <= 0) - return fdc_err(fdcu, bootverbose? "output ready timeout\n": 0); - - /* Send the command and return */ - outb(baseport+FDDATA, x); - TRACE1("[0x%x->FDDATA]", x); - return (0); -} - -/****************************************************************************/ -/* fdopen/fdclose */ -/****************************************************************************/ -int -Fdopen(dev_t dev, int flags, int mode, struct proc *p) -{ - fdu_t fdu = FDUNIT(minor(dev)); - int type = FDTYPE(minor(dev)); - fdc_p fdc; - - /* check bounds */ - if (fdu >= NFD) - return(ENXIO); - fdc = fd_data[fdu].fdc; - if ((fdc == NULL) || (fd_data[fdu].type == NO_TYPE)) - return(ENXIO); - if (type > NUMDENS) - return(ENXIO); -#ifdef PC98 - if (pc98_fd_check_ready(fdu) == -1) - return(EIO); -#endif - if (type == 0) - type = fd_data[fdu].type; -#ifndef PC98 - else { - /* - * For each type of basic drive, make sure we are trying - * to open a type it can do, - */ - if (type != fd_data[fdu].type) { - switch (fd_data[fdu].type) { - case FD_360: - return(ENXIO); - case FD_720: - if ( type != FD_820 - && type != FD_800 - ) - return(ENXIO); - break; - case FD_1200: - switch (type) { - case FD_1480: - type = FD_1480in5_25; - break; - case FD_1440: - type = FD_1440in5_25; - break; - case FD_820: - type = FD_820in5_25; - break; - case FD_800: - type = FD_800in5_25; - break; - case FD_720: - type = FD_720in5_25; - break; - case FD_360: - type = FD_360in5_25; - break; - default: - return(ENXIO); - } - break; - case FD_1440: - if ( type != FD_1720 - && type != FD_1480 - && type != FD_1200 - && type != FD_820 - && type != FD_800 - && type != FD_720 - ) - return(ENXIO); - break; - } - } - } -#endif - fd_data[fdu].ft = fd_types + type - 1; - fd_data[fdu].flags |= FD_OPEN; - - return 0; -} - -int -fdclose(dev_t dev, int flags, int mode, struct proc *p) -{ - fdu_t fdu = FDUNIT(minor(dev)); - - fd_data[fdu].flags &= ~FD_OPEN; - fd_data[fdu].options &= ~FDOPT_NORETRY; - - return(0); -} - -static int -fdread(dev_t dev, struct uio *uio, int ioflag) -{ - return (physio(fdstrategy, NULL, dev, 1, minphys, uio)); -} - -static int -fdwrite(dev_t dev, struct uio *uio, int ioflag) -{ - return (physio(fdstrategy, NULL, dev, 0, minphys, uio)); -} - - -/****************************************************************************/ -/* fdstrategy */ -/****************************************************************************/ -void -fdstrategy(struct buf *bp) -{ - unsigned nblocks, blknum, cando; - int s; - fdcu_t fdcu; - fdu_t fdu; - fdc_p fdc; - fd_p fd; - size_t fdblk; - - fdu = FDUNIT(minor(bp->b_dev)); - fd = &fd_data[fdu]; - fdc = fd->fdc; - fdcu = fdc->fdcu; -#ifdef FDC_YE - if (fd->type == NO_TYPE) { - bp->b_error = ENXIO; - bp->b_flags |= B_ERROR; - /* - * I _refuse_ to use a goto - */ - biodone(bp); - return; - }; -#endif - - fdblk = 128 << (fd->ft->secsize); - if (!(bp->b_flags & B_FORMAT)) { - if ((fdu >= NFD) || (bp->b_blkno < 0)) { - printf( - "fd%d: fdstrat: bad request blkno = %lu, bcount = %ld\n", - fdu, (u_long)bp->b_blkno, bp->b_bcount); - bp->b_error = EINVAL; - bp->b_flags |= B_ERROR; - goto bad; - } - if ((bp->b_bcount % fdblk) != 0) { - bp->b_error = EINVAL; - bp->b_flags |= B_ERROR; - goto bad; - } - } - - /* - * Set up block calculations. - */ - if (bp->b_blkno > 20000000) { - /* - * Reject unreasonably high block number, prevent the - * multiplication below from overflowing. - */ - bp->b_error = EINVAL; - bp->b_flags |= B_ERROR; - goto bad; - } - blknum = (unsigned) bp->b_blkno * DEV_BSIZE/fdblk; - nblocks = fd->ft->size; - bp->b_resid = 0; -#ifdef PC98 -#define B_XXX2 0x8000000 - if (bp->b_flags & B_XXX2) { - blknum *= 2; - bp->b_blkno *= 2; - bp->b_flags &= ~B_XXX2; - } -#endif - if (blknum + (bp->b_bcount / fdblk) > nblocks) { - if (blknum <= nblocks) { - cando = (nblocks - blknum) * fdblk; - bp->b_resid = bp->b_bcount - cando; - if (cando == 0) - goto bad; /* not actually bad but EOF */ - } else { - bp->b_error = EINVAL; - bp->b_flags |= B_ERROR; - goto bad; - } - } - bp->b_pblkno = bp->b_blkno; - s = splbio(); - bufqdisksort(&fdc->head, bp); - untimeout(fd_turnoff, (caddr_t)fdu, fd->toffhandle); /* a good idea */ - - /* Tell devstat we are starting on the transaction */ - devstat_start_transaction(&fd->device_stats); - - fdstart(fdcu); - splx(s); - return; - -bad: - biodone(bp); -} - -/***************************************************************\ -* fdstart * -* We have just queued something.. if the controller is not busy * -* then simulate the case where it has just finished a command * -* So that it (the interrupt routine) looks on the queue for more* -* work to do and picks up what we just added. * -* If the controller is already busy, we need do nothing, as it * -* will pick up our work when the present work completes * -\***************************************************************/ -static void -fdstart(fdcu_t fdcu) -{ - int s; - - s = splbio(); - if(fdc_data[fdcu].state == DEVIDLE) - { - fdintr(fdcu); - } - splx(s); -} - -static void -fd_iotimeout(void *arg1) -{ - fdc_p fdc; - fdcu_t fdcu; - int s; - - fdcu = (fdcu_t)arg1; - fdc = fdc_data + fdcu; - TRACE1("fd%d[fd_iotimeout()]", fdc->fdu); - - /* - * Due to IBM's brain-dead design, the FDC has a faked ready - * signal, hardwired to ready == true. Thus, any command - * issued if there's no diskette in the drive will _never_ - * complete, and must be aborted by resetting the FDC. - * Many thanks, Big Blue! - * The FDC must not be reset directly, since that would - * interfere with the state machine. Instead, pretend that - * the command completed but was invalid. The state machine - * will reset the FDC and retry once. - */ - s = splbio(); - fdc->status[0] = NE7_ST0_IC_IV; - fdc->flags &= ~FDC_STAT_VALID; - fdc->state = IOTIMEDOUT; - fdintr(fdcu); - splx(s); -} - -/* just ensure it has the right spl */ -static void -fd_pseudointr(void *arg1) -{ - fdcu_t fdcu = (fdcu_t)arg1; - int s; - - s = splbio(); - fdintr(fdcu); - splx(s); -} - -/***********************************************************************\ -* fdintr * -* keep calling the state machine until it returns a 0 * -* ALWAYS called at SPLBIO * -\***********************************************************************/ -static void -fdintr(fdcu_t fdcu) -{ - fdc_p fdc = fdc_data + fdcu; - while(fdstate(fdcu, fdc)) - ; -} - -#ifdef FDC_YE -/* - * magic pseudo-DMA initialization for YE FDC. Sets count and - * direction - */ -#define SET_BCDR(wr,cnt,port) outb(port,(((cnt)-1) & 0xff)); \ - outb(port+1,((wr ? 0x80 : 0) | ((((cnt)-1) >> 8) & 0x7f))) - -/* - * fdcpio(): perform programmed IO read/write for YE PCMCIA floppy - */ -static int fdcpio(fdcu_t fdcu, long flags, caddr_t addr, u_int count) -{ - u_char *cptr = (u_char *)addr; - fdc_p fdc = &fdc_data[fdcu]; - int io = fdc->baseport; - - if (flags & B_READ) { - if (fdc->state != PIOREAD) { - fdc->state = PIOREAD; - return(0); - }; - SET_BCDR(0,count,io); - insb(io+FDC_YE_DATAPORT,cptr,count); - } else { - outsb(io+FDC_YE_DATAPORT,cptr,count); - SET_BCDR(0,count,io); - }; - return(1); -} -#endif /* FDC_YE */ - -/***********************************************************************\ -* The controller state machine. * -* if it returns a non zero value, it should be called again immediatly * -\***********************************************************************/ -static int -fdstate(fdcu_t fdcu, fdc_p fdc) -{ - int read, format, head, i, sec = 0, sectrac, st0, cyl, st3; - unsigned blknum = 0, b_cylinder = 0; - fdu_t fdu = fdc->fdu; - fd_p fd; - register struct buf *bp; - struct fd_formb *finfo = NULL; - size_t fdblk; - - bp = fdc->bp; - if (bp == NULL) { - bp = bufq_first(&fdc->head); - if (bp != NULL) { - bufq_remove(&fdc->head, bp); - fdc->bp = bp; - } - } - if (bp == NULL) { - /***********************************************\ - * nothing left for this controller to do * - * Force into the IDLE state, * - \***********************************************/ - fdc->state = DEVIDLE; - if(fdc->fd) - { - printf("fd%d: unexpected valid fd pointer\n", - fdc->fdu); - fdc->fd = (fd_p) 0; - fdc->fdu = -1; - } - TRACE1("[fdc%d IDLE]", fdcu); - return(0); - } - fdu = FDUNIT(minor(bp->b_dev)); - fd = fd_data + fdu; - fdblk = 128 << fd->ft->secsize; - if (fdc->fd && (fd != fdc->fd)) - { - printf("fd%d: confused fd pointers\n", fdu); - } - read = bp->b_flags & B_READ; - format = bp->b_flags & B_FORMAT; - if(format) { - finfo = (struct fd_formb *)bp->b_data; - fd->skip = (char *)&(finfo->fd_formb_cylno(0)) - - (char *)finfo; - } - if (fdc->state == DOSEEK || fdc->state == SEEKCOMPLETE) { - blknum = (unsigned) bp->b_pblkno * DEV_BSIZE/fdblk + - fd->skip/fdblk; - b_cylinder = blknum / (fd->ft->sectrac * fd->ft->heads); - } - TRACE1("fd%d", fdu); - TRACE1("[%s]", fdstates[fdc->state]); - TRACE1("(0x%x)", fd->flags); - untimeout(fd_turnoff, (caddr_t)fdu, fd->toffhandle); - fd->toffhandle = timeout(fd_turnoff, (caddr_t)fdu, 4 * hz); - switch (fdc->state) - { - case DEVIDLE: - case FINDWORK: /* we have found new work */ - fdc->retry = 0; - fd->skip = 0; - fdc->fd = fd; - fdc->fdu = fdu; -#ifdef PC98 - pc98_trans = fd->ft->trans; - if (pc98_trans_prev != pc98_trans) { - int i; - set_density(fdcu, fdu); - for (i = 0; i < 10; i++) { - outb(0x5f, 0); - outb(0x5f, 0); - } - pc98_trans_prev = pc98_trans; - } - if (pc98_trans != fd->pc98_trans) { - if (pc98_trans != 1 && - (PC98_SYSTEM_PARAMETER(0x5ae) >> fdu) & 0x01) { - outb(0x4be, (fdu << 5) | 0x10 | (pc98_trans >> 1)); - outb(0x5f, 0); - outb(0x5f, 0); - } - fd->pc98_trans = pc98_trans; - } -#else - outb(fdc->baseport+FDCTL, fd->ft->trans); -#endif - TRACE1("[0x%x->FDCTL]", fd->ft->trans); - /*******************************************************\ - * If the next drive has a motor startup pending, then * - * it will start up in its own good time * - \*******************************************************/ - if(fd->flags & FD_MOTOR_WAIT) - { - fdc->state = MOTORWAIT; - return(0); /* come back later */ - } - /*******************************************************\ - * Maybe if it's not starting, it SHOULD be starting * - \*******************************************************/ -#ifdef EPSON_NRDISK - if (fdu != nrdu) { - if (!(fd->flags & FD_MOTOR)) - { - fdc->state = MOTORWAIT; - fd_turnon(fdu); - return(0); - } - else /* at least make sure we are selected */ - { - set_motor(fdcu, fd->fdsu, TURNON); - } - } -#else /* !EPSON_NRDISK */ - if (!(fd->flags & FD_MOTOR)) - { - fdc->state = MOTORWAIT; - fd_turnon(fdu); - return(0); - } - else /* at least make sure we are selected */ - { - set_motor(fdcu, fd->fdsu, TURNON); - } -#endif - if (fdc->flags & FDC_NEEDS_RESET) { - fdc->state = RESETCTLR; - fdc->flags &= ~FDC_NEEDS_RESET; - } else - fdc->state = DOSEEK; - break; - case DOSEEK: - if (b_cylinder == (unsigned)fd->track) - { - fdc->state = SEEKCOMPLETE; - break; - } -#ifdef PC98 - pc98_fd_check_ready(fdu); -#endif - if (fd_cmd(fdcu, 3, NE7CMD_SEEK, - fd->fdsu, b_cylinder * fd->ft->steptrac, - 0)) - { - /* - * seek command not accepted, looks like - * the FDC went off to the Saints... - */ - fdc->retry = 6; /* try a reset */ - return(retrier(fdcu)); - } - fd->track = FD_NO_TRACK; - fdc->state = SEEKWAIT; - return(0); /* will return later */ - case SEEKWAIT: - /* allow heads to settle */ - timeout(fd_pseudointr, (caddr_t)fdcu, hz / 16); - fdc->state = SEEKCOMPLETE; - return(0); /* will return later */ - case SEEKCOMPLETE : /* SEEK DONE, START DMA */ - /* Make sure seek really happened*/ - if(fd->track == FD_NO_TRACK) - { - int descyl = b_cylinder * fd->ft->steptrac; - do { - /* - * This might be a "ready changed" interrupt, - * which cannot really happen since the - * RDY pin is hardwired to + 5 volts. This - * generally indicates a "bouncing" intr - * line, so do one of the following: - * - * When running on an enhanced FDC that is - * known to not go stuck after responding - * with INVALID, fetch all interrupt states - * until seeing either an INVALID or a - * real interrupt condition. - * - * When running on a dumb old NE765, give - * up immediately. The controller will - * provide up to four dummy RC interrupt - * conditions right after reset (for the - * corresponding four drives), so this is - * our only chance to get notice that it - * was not the FDC that caused the interrupt. - */ - if (fd_sense_int(fdc, &st0, &cyl) - == FD_NOT_VALID) - return 0; - if(fdc->fdct == FDC_NE765 - && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC) - return 0; /* hope for a real intr */ - } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC); - - if (0 == descyl) - { - int failed = 0; - /* - * seek to cyl 0 requested; make sure we are - * really there - */ - if (fd_sense_drive_status(fdc, &st3)) - failed = 1; -#ifdef EPSON_NRDISK - if (fdu == nrdu) st3 = NE7_ST3_T0; -#endif /* EPSON_NRDISK */ - if ((st3 & NE7_ST3_T0) == 0) { - printf( - "fd%d: Seek to cyl 0, but not really there (ST3 = %b)\n", - fdu, st3, NE7_ST3BITS); - failed = 1; - } - - if (failed) - { - if(fdc->retry < 3) - fdc->retry = 3; - return(retrier(fdcu)); - } - } -#ifdef EPSON_NRDISK - if (fdu == nrdu) cyl = descyl; -#endif - - if (cyl != descyl) - { - printf( - "fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n", - fdu, descyl, cyl, st0); - if (fdc->retry < 3) - fdc->retry = 3; - return(retrier(fdcu)); - } - } - - fd->track = b_cylinder; -#ifdef EPSON_NRDISK - if (fdu != nrdu) { -#endif /* EPSON_NRDISK */ -#ifdef FDC_YE - if (!(fdc->flags & FDC_PCMCIA)) -#endif - isa_dmastart(bp->b_flags, bp->b_data+fd->skip, - format ? bp->b_bcount : fdblk, fdc->dmachan); - sectrac = fd->ft->sectrac; - sec = blknum % (sectrac * fd->ft->heads); - head = sec / sectrac; - sec = sec % sectrac + 1; - fd->hddrv = ((head&1)<<2)+fdu; - if(format || !read) - { - /* make sure the drive is writable */ - if(fd_sense_drive_status(fdc, &st3) != 0) - { - /* stuck controller? */ - isa_dmadone(bp->b_flags, bp->b_data + fd->skip, - format ? bp->b_bcount : fdblk, - fdc->dmachan); - fdc->retry = 6; /* reset the beast */ - return(retrier(fdcu)); - } - if(st3 & NE7_ST3_WP) - { - /* - * XXX YES! this is ugly. - * in order to force the current operation - * to fail, we will have to fake an FDC - * error - all error handling is done - * by the retrier() - */ - fdc->status[0] = NE7_ST0_IC_AT; - fdc->status[1] = NE7_ST1_NW; - fdc->status[2] = 0; - fdc->status[3] = fd->track; - fdc->status[4] = head; - fdc->status[5] = sec; - fdc->retry = 8; /* break out immediately */ - fdc->state = IOTIMEDOUT; /* not really... */ - return (1); - } - } - - if(format) - { -#ifdef FDC_YE - if (fdc->flags & FDC_PCMCIA) - (void)fdcpio(fdcu,bp->b_flags, - bp->b_data+fd->skip, - bp->b_bcount); -#endif - /* formatting */ - if(fd_cmd(fdcu, 6, - NE7CMD_FORMAT, - head << 2 | fdu, - finfo->fd_formb_secshift, - finfo->fd_formb_nsecs, - finfo->fd_formb_gaplen, - finfo->fd_formb_fillbyte, - 0)) - { - /* controller fell over */ - isa_dmadone(bp->b_flags, bp->b_data + fd->skip, - format ? bp->b_bcount : fdblk, - fdc->dmachan); - fdc->retry = 6; - return(retrier(fdcu)); - } - } - else - { -#ifdef FDC_YE - if (fdc->flags & FDC_PCMCIA) { - /* - * this seems to be necessary even when - * reading data - */ - SET_BCDR(1,fdblk,fdc->baseport); - - /* - * perform the write pseudo-DMA before - * the WRITE command is sent - */ - if (!read) - (void)fdcpio(fdcu,bp->b_flags, - bp->b_data+fd->skip, - fdblk); - } -#endif - if (fd_cmd(fdcu, 9, - (read ? NE7CMD_READ : NE7CMD_WRITE), - head << 2 | fdu, /* head & unit */ - fd->track, /* track */ - head, - sec, /* sector + 1 */ - fd->ft->secsize, /* sector size */ - sectrac, /* sectors/track */ - fd->ft->gap, /* gap size */ - fd->ft->datalen, /* data length */ - 0)) - { - /* the beast is sleeping again */ - isa_dmadone(bp->b_flags, bp->b_data + fd->skip, - format ? bp->b_bcount : fdblk, - fdc->dmachan); - fdc->retry = 6; - return(retrier(fdcu)); - } - } -#ifdef FDC_YE - if (fdc->flags & FDC_PCMCIA) - /* - * if this is a read, then simply await interrupt - * before performing PIO - */ - if (read && !fdcpio(fdcu,bp->b_flags, - bp->b_data+fd->skip,fdblk)) { - fd->tohandle = timeout(fd_iotimeout, - (caddr_t)fdcu, hz); - return(0); /* will return later */ - }; - - /* - * write (or format) operation will fall through and - * await completion interrupt - */ -#endif - fdc->state = IOCOMPLETE; - fd->tohandle = timeout(fd_iotimeout, (caddr_t)fdcu, hz); - return(0); /* will return later */ -#ifdef EPSON_NRDISK - } - else { - nrdblkn = (nrd_t)((unsigned long)bp->b_blkno*DEV_BSIZE/fdblk - + fd->skip/fdblk); - nrd_LED_on(); - nrd_addrset(fdblk * nrdblkn); - while (!nrd_check_ready()) DELAY(1); - if (read) epson_insw(P_NRD_DATA, - bp->b_data + fd->skip, - fdblk / sizeof(short)); - else epson_outsw(P_NRD_DATA, - bp->b_data + fd->skip, - (format ? bp->b_bcount : fdblk) - / sizeof(short)); - - blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/fdblk - + fd->skip/fdblk; - sectrac = fd->ft->sectrac; - sec = blknum % (sectrac * fd->ft->heads); - head = sec / sectrac; - sec = sec % sectrac + 1; - fd->hddrv = ((head&1)<<2)+fdu; - - if (nrdsec++ >= nrd_sec()) - nrdaddr = (nrd_t)(fd->track * 8 + head * 4); - nrdsec = sec; - fdc->state = IOCOMPLETE; - } -#endif -#ifdef FDC_YE - case PIOREAD: - /* - * actually perform the PIO read. The IOCOMPLETE case - * removes the timeout for us. - */ - (void)fdcpio(fdcu,bp->b_flags,bp->b_data+fd->skip,fdblk); - fdc->state = IOCOMPLETE; - /* FALLTHROUGH */ -#endif - case IOCOMPLETE: /* IO DONE, post-analyze */ -#ifdef EPSON_NRDISK - if (fdu != nrdu) - untimeout(fd_iotimeout, (caddr_t)fdcu, fd->tohandle); -#else - untimeout(fd_iotimeout, (caddr_t)fdcu, fd->tohandle); -#endif - - if (fd_read_status(fdc, fd->fdsu)) - { - isa_dmadone(bp->b_flags, bp->b_data + fd->skip, - format ? bp->b_bcount : fdblk, - fdc->dmachan); - if (fdc->retry < 6) - fdc->retry = 6; /* force a reset */ - return retrier(fdcu); - } - - fdc->state = IOTIMEDOUT; - - /* FALLTHROUGH */ - - case IOTIMEDOUT: -#ifdef EPSON_NRDISK - if (fdu != nrdu) { -#endif /* EPSON_NRDISK */ -#ifdef FDC_YE - if (!(fdc->flags & FDC_PCMCIA)) -#endif - isa_dmadone(bp->b_flags, bp->b_data + fd->skip, - format ? bp->b_bcount : fdblk, fdc->dmachan); -#ifdef EPSON_NRDISK - } - else nrd_LED_off(); -#endif /* EPSON_NRDISK */ - if (fdc->status[0] & NE7_ST0_IC) - { - if ((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT - && fdc->status[1] & NE7_ST1_OR) { - /* - * DMA overrun. Someone hogged the bus - * and didn't release it in time for the - * next FDC transfer. - * Just restart it, don't increment retry - * count. (vak) - */ - fdc->state = SEEKCOMPLETE; - return (1); - } - else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_IV - && fdc->retry < 6) - fdc->retry = 6; /* force a reset */ - else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT - && fdc->status[2] & NE7_ST2_WC - && fdc->retry < 3) - fdc->retry = 3; /* force recalibrate */ - return(retrier(fdcu)); - } - /* All OK */ - fd->skip += fdblk; - if (!format && fd->skip < bp->b_bcount - bp->b_resid) - { - /* set up next transfer */ - fdc->state = DOSEEK; - } - else - { - /* ALL DONE */ - fd->skip = 0; - fdc->bp = NULL; - /* Tell devstat we have finished with the transaction */ - devstat_end_transaction(&fd->device_stats, - bp->b_bcount - bp->b_resid, - DEVSTAT_TAG_NONE, - (bp->b_flags & B_READ) ? - DEVSTAT_READ : DEVSTAT_WRITE); - biodone(bp); - fdc->fd = (fd_p) 0; - fdc->fdu = -1; - fdc->state = FINDWORK; - } - return(1); - case RESETCTLR: - fdc_reset(fdc); - fdc->retry++; - fdc->state = RESETCOMPLETE; - return (0); - case RESETCOMPLETE: - /* - * Discard all the results from the reset so that they - * can't cause an unexpected interrupt later. - */ - for (i = 0; i < 4; i++) - (void)fd_sense_int(fdc, &st0, &cyl); - fdc->state = STARTRECAL; - /* Fall through. */ - case STARTRECAL: -#ifdef PC98 - pc98_fd_check_ready(fdu); -#endif - if(fd_cmd(fdcu, - 2, NE7CMD_RECAL, fdu, - 0)) /* Recalibrate Function */ - { - /* arrgl */ - fdc->retry = 6; - return(retrier(fdcu)); - } - fdc->state = RECALWAIT; - return(0); /* will return later */ - case RECALWAIT: - /* allow heads to settle */ - timeout(fd_pseudointr, (caddr_t)fdcu, hz / 8); - fdc->state = RECALCOMPLETE; - return(0); /* will return later */ - case RECALCOMPLETE: - do { - /* - * See SEEKCOMPLETE for a comment on this: - */ - if (fd_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID) - return 0; - if(fdc->fdct == FDC_NE765 - && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC) - return 0; /* hope for a real intr */ - } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC); -#ifdef EPSON_NRDISK - if (fdu == nrdu) { - st0 = NE7_ST0_IC_NT; - cyl = 0; - } -#endif - if ((st0 & NE7_ST0_IC) != NE7_ST0_IC_NT || cyl != 0) - { - if(fdc->retry > 3) - /* - * a recalibrate from beyond cylinder 77 - * will "fail" due to the FDC limitations; - * since people used to complain much about - * the failure message, try not logging - * this one if it seems to be the first - * time in a line - */ - printf("fd%d: recal failed ST0 %b cyl %d\n", - fdu, st0, NE7_ST0BITS, cyl); - if(fdc->retry < 3) fdc->retry = 3; - return(retrier(fdcu)); - } - fd->track = 0; - /* Seek (probably) necessary */ - fdc->state = DOSEEK; - return(1); /* will return immediatly */ - case MOTORWAIT: - if(fd->flags & FD_MOTOR_WAIT) - { - return(0); /* time's not up yet */ - } - if (fdc->flags & FDC_NEEDS_RESET) { - fdc->state = RESETCTLR; - fdc->flags &= ~FDC_NEEDS_RESET; - } else { - /* - * If all motors were off, then the controller was - * reset, so it has lost track of the current - * cylinder. Recalibrate to handle this case. - */ - fdc->state = STARTRECAL; - } - return(1); /* will return immediatly */ - default: - printf("fdc%d: Unexpected FD int->", fdcu); - if (fd_read_status(fdc, fd->fdsu) == 0) - printf("FDC status :%x %x %x %x %x %x %x ", - fdc->status[0], - fdc->status[1], - fdc->status[2], - fdc->status[3], - fdc->status[4], - fdc->status[5], - fdc->status[6] ); - else - printf("No status available "); - if (fd_sense_int(fdc, &st0, &cyl) != 0) - { - printf("[controller is dead now]\n"); - return(0); - } - printf("ST0 = %x, PCN = %x\n", st0, cyl); - return(0); - } - /*XXX confusing: some branches return immediately, others end up here*/ - return(1); /* Come back immediatly to new state */ -} - -static int -retrier(fdcu) - fdcu_t fdcu; -{ - fdc_p fdc = fdc_data + fdcu; - register struct buf *bp; - - bp = fdc->bp; - - if(fd_data[FDUNIT(minor(bp->b_dev))].options & FDOPT_NORETRY) - goto fail; - switch(fdc->retry) - { - case 0: case 1: case 2: - fdc->state = SEEKCOMPLETE; - break; - case 3: case 4: case 5: - fdc->state = STARTRECAL; - break; - case 6: - fdc->state = RESETCTLR; - break; - case 7: - break; - default: - fail: - { - dev_t sav_b_dev = bp->b_dev; - /* Trick diskerr */ - bp->b_dev = makedev(major(bp->b_dev), - (FDUNIT(minor(bp->b_dev))<<3)|RAW_PART); - diskerr(bp, "fd", "hard error", LOG_PRINTF, - fdc->fd->skip / DEV_BSIZE, - (struct disklabel *)NULL); - bp->b_dev = sav_b_dev; - if (fdc->flags & FDC_STAT_VALID) - { - printf( - " (ST0 %b ST1 %b ST2 %b cyl %u hd %u sec %u)\n", - fdc->status[0], NE7_ST0BITS, - fdc->status[1], NE7_ST1BITS, - fdc->status[2], NE7_ST2BITS, - fdc->status[3], fdc->status[4], - fdc->status[5]); - } - else - printf(" (No status)\n"); - } - bp->b_flags |= B_ERROR; - bp->b_error = EIO; - bp->b_resid += bp->b_bcount - fdc->fd->skip; - fdc->bp = NULL; - - /* Tell devstat we have finished with the transaction */ - devstat_end_transaction(&fdc->fd->device_stats, - bp->b_bcount - bp->b_resid, - DEVSTAT_TAG_NONE, - (bp->b_flags & B_READ) ? DEVSTAT_READ : - DEVSTAT_WRITE); - fdc->fd->skip = 0; - biodone(bp); - fdc->state = FINDWORK; - fdc->flags |= FDC_NEEDS_RESET; - fdc->fd = (fd_p) 0; - fdc->fdu = -1; - return(1); - } - fdc->retry++; - return(1); -} - -static int -fdformat(dev, finfo, p) - dev_t dev; - struct fd_formb *finfo; - struct proc *p; -{ - fdu_t fdu; - fd_p fd; - - struct buf *bp; - int rv = 0, s; - size_t fdblk; - - fdu = FDUNIT(minor(dev)); - fd = &fd_data[fdu]; - fdblk = 128 << fd->ft->secsize; - - /* set up a buffer header for fdstrategy() */ - bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT); - if(bp == 0) - return ENOBUFS; - /* - * keep the process from being swapped - */ - p->p_flag |= P_PHYSIO; - bzero((void *)bp, sizeof(struct buf)); - bp->b_flags = B_BUSY | B_PHYS | B_FORMAT; - bp->b_proc = p; - - /* - * calculate a fake blkno, so fdstrategy() would initiate a - * seek to the requested cylinder - */ - bp->b_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads) - + finfo->head * fd->ft->sectrac) * fdblk / DEV_BSIZE; - - bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs; - bp->b_data = (caddr_t)finfo; - - /* now do the format */ - bp->b_dev = dev; - 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; - /* - * allow the process to be swapped - */ - p->p_flag &= ~P_PHYSIO; - free(bp, M_TEMP); - return rv; -} - -/* - * TODO: don't allocate buffer on stack. - */ - -static int -fdioctl(dev, cmd, addr, flag, p) - dev_t dev; - u_long cmd; - caddr_t addr; - int flag; - struct proc *p; -{ - fdu_t fdu = FDUNIT(minor(dev)); - fd_p fd = &fd_data[fdu]; - size_t fdblk; - - struct fd_type *fdt; - struct disklabel *dl; - char buffer[DEV_BSIZE]; - int error = 0; - - fdblk = 128 << fd->ft->secsize; - -#ifdef PC98 - pc98_fd_check_ready(fdu); -#endif - switch (cmd) - { - case DIOCGDINFO: - bzero(buffer, sizeof (buffer)); - dl = (struct disklabel *)buffer; - dl->d_secsize = fdblk; - fdt = fd_data[FDUNIT(minor(dev))].ft; - dl->d_secpercyl = fdt->size / fdt->tracks; - dl->d_type = DTYPE_FLOPPY; - - if (readdisklabel(dkmodpart(dev, RAW_PART), fdstrategy, dl) - == NULL) - error = 0; - else - error = EINVAL; - - *(struct disklabel *)addr = *dl; - break; - - case DIOCSDINFO: - if ((flag & FWRITE) == 0) - error = EBADF; - break; - - case DIOCWLABEL: - if ((flag & FWRITE) == 0) - error = EBADF; - break; - - case DIOCWDINFO: - if ((flag & FWRITE) == 0) - { - error = EBADF; - break; - } - - dl = (struct disklabel *)addr; - - if ((error = setdisklabel((struct disklabel *)buffer, dl, - (u_long)0)) != 0) - break; - - error = writedisklabel(dev, fdstrategy, - (struct disklabel *)buffer); - break; - case FD_FORM: - if((flag & FWRITE) == 0) - error = EBADF; /* must be opened for writing */ - else if(((struct fd_formb *)addr)->format_version != - FD_FORMAT_VERSION) - error = EINVAL; /* wrong version of formatting prog */ - else - error = fdformat(dev, (struct fd_formb *)addr, p); - break; - - case FD_GTYPE: /* get drive type */ - *(struct fd_type *)addr = *fd->ft; - break; - - case FD_STYPE: /* set drive type */ - /* this is considered harmful; only allow for superuser */ - if(suser(p->p_ucred, &p->p_acflag) != 0) - return EPERM; - *fd->ft = *(struct fd_type *)addr; - break; - - case FD_GOPTS: /* get drive options */ - *(int *)addr = fd->options; - break; - - case FD_SOPTS: /* set drive options */ - fd->options = *(int *)addr; - break; - - default: - error = ENOTTY; - break; - } - return (error); -} - - -static fd_devsw_installed = 0; - -static void fd_drvinit(void *notused ) -{ - - if( ! fd_devsw_installed ) { - cdevsw_add_generic(BDEV_MAJOR,CDEV_MAJOR, &fd_cdevsw); - fd_devsw_installed = 1; - } -} - -SYSINIT(fddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,fd_drvinit,NULL) - - -#endif - -/* - * Hello emacs, these are the - * Local Variables: - * c-indent-level: 8 - * c-continued-statement-offset: 8 - * c-continued-brace-offset: 0 - * c-brace-offset: -8 - * c-brace-imaginary-offset: 0 - * c-argdecl-indent: 8 - * c-label-offset: -8 - * c++-hanging-braces: 1 - * c++-access-specifier-offset: -8 - * c++-empty-arglist-indent: 8 - * c++-friend-offset: 0 - * End: - */ |