Home | History | Annotate | Line # | Download | only in dev
hdfd.c revision 1.1
      1  1.1  leo /*	$NetBSD: hdfd.c,v 1.1 1996/11/09 22:27:25 leo Exp $	*/
      2  1.1  leo 
      3  1.1  leo /*-
      4  1.1  leo  * Copyright (c) 1996 Leo Weppelman
      5  1.1  leo  * Copyright (c) 1993, 1994, 1995, 1996
      6  1.1  leo  *	Charles M. Hannum.  All rights reserved.
      7  1.1  leo  * Copyright (c) 1990 The Regents of the University of California.
      8  1.1  leo  * All rights reserved.
      9  1.1  leo  *
     10  1.1  leo  * This code is derived from software contributed to Berkeley by
     11  1.1  leo  * Don Ahn.
     12  1.1  leo  *
     13  1.1  leo  * Redistribution and use in source and binary forms, with or without
     14  1.1  leo  * modification, are permitted provided that the following conditions
     15  1.1  leo  * are met:
     16  1.1  leo  * 1. Redistributions of source code must retain the above copyright
     17  1.1  leo  *    notice, this list of conditions and the following disclaimer.
     18  1.1  leo  * 2. Redistributions in binary form must reproduce the above copyright
     19  1.1  leo  *    notice, this list of conditions and the following disclaimer in the
     20  1.1  leo  *    documentation and/or other materials provided with the distribution.
     21  1.1  leo  * 3. All advertising materials mentioning features or use of this software
     22  1.1  leo  *    must display the following acknowledgement:
     23  1.1  leo  *	This product includes software developed by the University of
     24  1.1  leo  *	California, Berkeley and its contributors.
     25  1.1  leo  * 4. Neither the name of the University nor the names of its contributors
     26  1.1  leo  *    may be used to endorse or promote products derived from this software
     27  1.1  leo  *    without specific prior written permission.
     28  1.1  leo  *
     29  1.1  leo  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     30  1.1  leo  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     31  1.1  leo  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     32  1.1  leo  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     33  1.1  leo  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     34  1.1  leo  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     35  1.1  leo  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     36  1.1  leo  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     37  1.1  leo  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     38  1.1  leo  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     39  1.1  leo  * SUCH DAMAGE.
     40  1.1  leo  *
     41  1.1  leo  *	@(#)fd.c	7.4 (Berkeley) 5/25/91
     42  1.1  leo  */
     43  1.1  leo 
     44  1.1  leo #include <sys/param.h>
     45  1.1  leo #include <sys/systm.h>
     46  1.1  leo #include <sys/kernel.h>
     47  1.1  leo #include <sys/file.h>
     48  1.1  leo #include <sys/ioctl.h>
     49  1.1  leo #include <sys/device.h>
     50  1.1  leo #include <sys/disklabel.h>
     51  1.1  leo #include <sys/dkstat.h>
     52  1.1  leo #include <sys/disk.h>
     53  1.1  leo #include <sys/buf.h>
     54  1.1  leo #include <sys/uio.h>
     55  1.1  leo #include <sys/syslog.h>
     56  1.1  leo #include <sys/queue.h>
     57  1.1  leo #include <sys/conf.h>
     58  1.1  leo #include <sys/device.h>
     59  1.1  leo 
     60  1.1  leo #include <machine/cpu.h>
     61  1.1  leo #include <machine/bus.h>
     62  1.1  leo #include <machine/iomap.h>
     63  1.1  leo #include <machine/mfp.h>
     64  1.1  leo 
     65  1.1  leo #include <atari/dev/hdfdreg.h>
     66  1.1  leo #include <atari/atari/device.h>
     67  1.1  leo 
     68  1.1  leo /*
     69  1.1  leo  * {b,c}devsw[] function prototypes
     70  1.1  leo  */
     71  1.1  leo dev_type_open(fdopen);
     72  1.1  leo dev_type_close(fdclose);
     73  1.1  leo dev_type_read(fdread);
     74  1.1  leo dev_type_write(fdwrite);
     75  1.1  leo dev_type_ioctl(fdioctl);
     76  1.1  leo dev_type_size(fdsize);
     77  1.1  leo dev_type_dump(fddump);
     78  1.1  leo 
     79  1.1  leo volatile u_char	*fdio_addr;
     80  1.1  leo 
     81  1.1  leo #define wrt_fdc_reg(reg, val)	{ fdio_addr[reg] = val; }
     82  1.1  leo #define rd_fdc_reg(reg)		( fdio_addr[reg] )
     83  1.1  leo 
     84  1.1  leo #define	fdc_ienable()		MFP2->mf_ierb |= IB_DCHG;
     85  1.1  leo 
     86  1.1  leo /*
     87  1.1  leo  * Interface to the pseudo-dma handler
     88  1.1  leo  */
     89  1.1  leo void	fddma_intr(void);
     90  1.1  leo caddr_t	fddmaaddr  = NULL;
     91  1.1  leo int	fddmalen   = 0;
     92  1.1  leo 
     93  1.1  leo /*
     94  1.1  leo  * Argument to fdcintr.....
     95  1.1  leo  */
     96  1.1  leo static void	*intr_arg = NULL; /* XXX: arg. to intr_establish() */
     97  1.1  leo 
     98  1.1  leo 
     99  1.1  leo #define FDUNIT(dev)	(minor(dev) / 8)
    100  1.1  leo #define FDTYPE(dev)	(minor(dev) % 8)
    101  1.1  leo 
    102  1.1  leo #define b_cylin b_resid
    103  1.1  leo 
    104  1.1  leo enum fdc_state {
    105  1.1  leo 	DEVIDLE = 0,
    106  1.1  leo 	MOTORWAIT,
    107  1.1  leo 	DOSEEK,
    108  1.1  leo 	SEEKWAIT,
    109  1.1  leo 	SEEKTIMEDOUT,
    110  1.1  leo 	SEEKCOMPLETE,
    111  1.1  leo 	DOIO,
    112  1.1  leo 	IOCOMPLETE,
    113  1.1  leo 	IOTIMEDOUT,
    114  1.1  leo 	DORESET,
    115  1.1  leo 	RESETCOMPLETE,
    116  1.1  leo 	RESETTIMEDOUT,
    117  1.1  leo 	DORECAL,
    118  1.1  leo 	RECALWAIT,
    119  1.1  leo 	RECALTIMEDOUT,
    120  1.1  leo 	RECALCOMPLETE,
    121  1.1  leo };
    122  1.1  leo 
    123  1.1  leo /* software state, per controller */
    124  1.1  leo struct fdc_softc {
    125  1.1  leo 	struct device	sc_dev;		/* boilerplate */
    126  1.1  leo 	struct fd_softc	*sc_fd[4];	/* pointers to children */
    127  1.1  leo 	TAILQ_HEAD(drivehead, fd_softc) sc_drives;
    128  1.1  leo 	enum fdc_state	sc_state;
    129  1.1  leo 	int		sc_errors;	/* number of retries so far */
    130  1.1  leo 	int		sc_overruns;	/* number of overruns so far */
    131  1.1  leo 	u_char		sc_status[7];	/* copy of registers */
    132  1.1  leo };
    133  1.1  leo 
    134  1.1  leo /* controller driver configuration */
    135  1.1  leo int	fdcprobe __P((struct device *, void *, void *));
    136  1.1  leo int	fdprint __P((void *, const char *));
    137  1.1  leo void	fdcattach __P((struct device *, struct device *, void *));
    138  1.1  leo 
    139  1.1  leo struct cfattach fdc_ca = {
    140  1.1  leo 	sizeof(struct fdc_softc), fdcprobe, fdcattach
    141  1.1  leo };
    142  1.1  leo 
    143  1.1  leo struct cfdriver fdc_cd = {
    144  1.1  leo 	NULL, "fdc", DV_DULL
    145  1.1  leo };
    146  1.1  leo 
    147  1.1  leo /*
    148  1.1  leo  * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
    149  1.1  leo  * we tell them apart.
    150  1.1  leo  */
    151  1.1  leo struct fd_type {
    152  1.1  leo 	int	sectrac;	/* sectors per track */
    153  1.1  leo 	int	heads;		/* number of heads */
    154  1.1  leo 	int	seccyl;		/* sectors per cylinder */
    155  1.1  leo 	int	secsize;	/* size code for sectors */
    156  1.1  leo 	int	datalen;	/* data len when secsize = 0 */
    157  1.1  leo 	int	steprate;	/* step rate and head unload time */
    158  1.1  leo 	int	gap1;		/* gap len between sectors */
    159  1.1  leo 	int	gap2;		/* formatting gap */
    160  1.1  leo 	int	tracks;		/* total num of tracks */
    161  1.1  leo 	int	size;		/* size of disk in sectors */
    162  1.1  leo 	int	step;		/* steps per cylinder */
    163  1.1  leo 	int	rate;		/* transfer speed code */
    164  1.1  leo 	char	*name;
    165  1.1  leo };
    166  1.1  leo 
    167  1.1  leo /*
    168  1.1  leo  * The order of entries in the following table is important -- BEWARE!
    169  1.1  leo  * The order of the types is the same as for the TT/Falcon....
    170  1.1  leo  */
    171  1.1  leo struct fd_type fd_types[] = {
    172  1.1  leo         /* 360kB in 720kB drive */
    173  1.1  leo         {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_125KBPS, "360KB"  },
    174  1.1  leo         /* 3.5" 720kB diskette */
    175  1.1  leo         {  9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_125KBPS, "720KB"  },
    176  1.1  leo         /* 1.44MB diskette */
    177  1.1  leo         { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_250KBPS, "1.44MB" },
    178  1.1  leo };
    179  1.1  leo 
    180  1.1  leo /* software state, per disk (with up to 4 disks per ctlr) */
    181  1.1  leo struct fd_softc {
    182  1.1  leo 	struct device	sc_dev;
    183  1.1  leo 	struct disk	sc_dk;
    184  1.1  leo 
    185  1.1  leo 	struct fd_type	*sc_deftype;	/* default type descriptor */
    186  1.1  leo 	struct fd_type	*sc_type;	/* current type descriptor */
    187  1.1  leo 
    188  1.1  leo 	daddr_t		sc_blkno;	/* starting block number */
    189  1.1  leo 	int		sc_bcount;	/* byte count left */
    190  1.1  leo 	int		sc_skip;	/* bytes already transferred */
    191  1.1  leo 	int		sc_nblks;	/* #blocks currently tranferring */
    192  1.1  leo 	int		sc_nbytes;	/* #bytes currently tranferring */
    193  1.1  leo 
    194  1.1  leo 	int		sc_drive;	/* physical unit number */
    195  1.1  leo 	int		sc_flags;
    196  1.1  leo #define	FD_OPEN		0x01		/* it's open */
    197  1.1  leo #define	FD_MOTOR	0x02		/* motor should be on */
    198  1.1  leo #define	FD_MOTOR_WAIT	0x04		/* motor coming up */
    199  1.1  leo 	int		sc_cylin;	/* where we think the head is */
    200  1.1  leo 
    201  1.1  leo 	void		*sc_sdhook;	/* saved shutdown hook for drive. */
    202  1.1  leo 
    203  1.1  leo 	TAILQ_ENTRY(fd_softc) sc_drivechain;
    204  1.1  leo 	int		sc_ops;		/* I/O ops since last switch */
    205  1.1  leo 	struct buf	sc_q;		/* head of buf chain */
    206  1.1  leo };
    207  1.1  leo 
    208  1.1  leo /* floppy driver configuration */
    209  1.1  leo int	fdprobe __P((struct device *, void *, void *));
    210  1.1  leo void	fdattach __P((struct device *, struct device *, void *));
    211  1.1  leo 
    212  1.1  leo struct cfattach hdfd_ca = {
    213  1.1  leo 	sizeof(struct fd_softc), fdprobe, fdattach
    214  1.1  leo };
    215  1.1  leo 
    216  1.1  leo struct cfdriver hdfd_cd = {
    217  1.1  leo 	NULL, "hdfd", DV_DISK
    218  1.1  leo };
    219  1.1  leo 
    220  1.1  leo void	fdstrategy __P((struct buf *));
    221  1.1  leo void	fdstart __P((struct fd_softc *));
    222  1.1  leo 
    223  1.1  leo struct dkdriver fddkdriver = { fdstrategy };
    224  1.1  leo 
    225  1.1  leo void	fd_set_motor __P((struct fdc_softc *fdc, int reset));
    226  1.1  leo void	fd_motor_off __P((void *arg));
    227  1.1  leo void	fd_motor_on __P((void *arg));
    228  1.1  leo int	fdcresult __P((struct fdc_softc *fdc));
    229  1.1  leo int	out_fdc __P((u_char x));
    230  1.1  leo void	fdc_ctrl_intr __P((struct clockframe *));
    231  1.1  leo void	fdcstart __P((struct fdc_softc *fdc));
    232  1.1  leo void	fdcstatus __P((struct device *dv, int n, char *s));
    233  1.1  leo void	fdctimeout __P((void *arg));
    234  1.1  leo void	fdcpseudointr __P((void *arg));
    235  1.1  leo int	fdcintr __P((void *));
    236  1.1  leo void	fdcretry __P((struct fdc_softc *fdc));
    237  1.1  leo void	fdfinish __P((struct fd_softc *fd, struct buf *bp));
    238  1.1  leo __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
    239  1.1  leo 
    240  1.1  leo int
    241  1.1  leo fdcprobe(parent, match, aux)
    242  1.1  leo 	struct device *parent;
    243  1.1  leo 	void *match, *aux;
    244  1.1  leo {
    245  1.1  leo 	int		rv   = 0;
    246  1.1  leo 	struct cfdata	*cfp = match;
    247  1.1  leo 
    248  1.1  leo 	if(strcmp("fdc", aux) || cfp->cf_unit != 0)
    249  1.1  leo 		return(0);
    250  1.1  leo 
    251  1.1  leo 	if (!atari_realconfig)
    252  1.1  leo 		return 0;
    253  1.1  leo 
    254  1.1  leo 	if (bus_space_map(NULL, 0xfff00000, NBPG, 0, (caddr_t*)&fdio_addr)) {
    255  1.1  leo 		printf("fdcprobe: cannot map io-area\n");
    256  1.1  leo 		return (0);
    257  1.1  leo 	}
    258  1.1  leo 
    259  1.1  leo #ifdef FD_DEBUG
    260  1.1  leo 	printf("fdcprobe: I/O mapping done va: %p\n", fdio_addr);
    261  1.1  leo #endif
    262  1.1  leo 
    263  1.1  leo 	/* reset */
    264  1.1  leo 	wrt_fdc_reg(fdout, 0);
    265  1.1  leo 	delay(100);
    266  1.1  leo 	wrt_fdc_reg(fdout, FDO_FRST);
    267  1.1  leo 
    268  1.1  leo 	/* see if it can handle a command */
    269  1.1  leo 	if (out_fdc(NE7CMD_SPECIFY) < 0)
    270  1.1  leo 		goto out;
    271  1.1  leo 	out_fdc(0xdf);
    272  1.1  leo 	out_fdc(7);
    273  1.1  leo 
    274  1.1  leo 	rv = 1;
    275  1.1  leo 
    276  1.1  leo  out:
    277  1.1  leo 	if (rv == 0)
    278  1.1  leo 		bus_space_unmap(NULL, (caddr_t)fdio_addr, NBPG);
    279  1.1  leo 
    280  1.1  leo 	return rv;
    281  1.1  leo }
    282  1.1  leo 
    283  1.1  leo /*
    284  1.1  leo  * Arguments passed between fdcattach and fdprobe.
    285  1.1  leo  */
    286  1.1  leo struct fdc_attach_args {
    287  1.1  leo 	int fa_drive;
    288  1.1  leo 	struct fd_type *fa_deftype;
    289  1.1  leo };
    290  1.1  leo 
    291  1.1  leo /*
    292  1.1  leo  * Print the location of a disk drive (called just before attaching the
    293  1.1  leo  * the drive).  If `fdc' is not NULL, the drive was found but was not
    294  1.1  leo  * in the system config file; print the drive name as well.
    295  1.1  leo  * Return QUIET (config_find ignores this if the device was configured) to
    296  1.1  leo  * avoid printing `fdN not configured' messages.
    297  1.1  leo  */
    298  1.1  leo int
    299  1.1  leo fdprint(aux, fdc)
    300  1.1  leo 	void *aux;
    301  1.1  leo 	const char *fdc;
    302  1.1  leo {
    303  1.1  leo 	register struct fdc_attach_args *fa = aux;
    304  1.1  leo 
    305  1.1  leo 	if (!fdc)
    306  1.1  leo 		printf(" drive %d", fa->fa_drive);
    307  1.1  leo 	return QUIET;
    308  1.1  leo }
    309  1.1  leo 
    310  1.1  leo void
    311  1.1  leo fdcattach(parent, self, aux)
    312  1.1  leo 	struct device *parent, *self;
    313  1.1  leo 	void *aux;
    314  1.1  leo {
    315  1.1  leo 	struct fdc_softc	*fdc = (void *)self;
    316  1.1  leo 	struct fdc_attach_args	fa;
    317  1.1  leo 	int			has_fifo;
    318  1.1  leo 
    319  1.1  leo 	has_fifo = 0;
    320  1.1  leo 
    321  1.1  leo 	fdc->sc_state = DEVIDLE;
    322  1.1  leo 	TAILQ_INIT(&fdc->sc_drives);
    323  1.1  leo 
    324  1.1  leo 	out_fdc(NE7CMD_CONFIGURE);
    325  1.1  leo 	if (out_fdc(0) == 0) {
    326  1.1  leo 		out_fdc(0x1a);	/* No polling, fifo depth = 10	*/
    327  1.1  leo 		out_fdc(0);
    328  1.1  leo 
    329  1.1  leo 		/* Retain configuration across resets	*/
    330  1.1  leo 		out_fdc(NE7CMD_LOCK);
    331  1.1  leo 		(void)fdcresult(fdc);
    332  1.1  leo 		has_fifo = 1;
    333  1.1  leo 	}
    334  1.1  leo 	else {
    335  1.1  leo 		(void)rd_fdc_reg(fddata);
    336  1.1  leo 		printf(": no fifo");
    337  1.1  leo 	}
    338  1.1  leo 
    339  1.1  leo 	printf("\n");
    340  1.1  leo 
    341  1.1  leo 	/*
    342  1.1  leo 	 * Setup the interrupt vector.
    343  1.1  leo 	 * XXX: While no int_establish() functions are available,
    344  1.1  leo 	 *      we do it the Dirty(Tm) way...
    345  1.1  leo 	 */
    346  1.1  leo 	{
    347  1.1  leo 		extern	u_long	uservects[];
    348  1.1  leo 		extern	void	mfp_hdfd_nf(void), mfp_hdfd_fifo(void);
    349  1.1  leo 
    350  1.1  leo 		uservects[22] = (u_long)(has_fifo ? mfp_hdfd_fifo:mfp_hdfd_nf);
    351  1.1  leo 	}
    352  1.1  leo 
    353  1.1  leo 	/*
    354  1.1  leo 	 * Setup the interrupt logic.
    355  1.1  leo 	 */
    356  1.1  leo 	MFP2->mf_iprb &= ~IB_DCHG;
    357  1.1  leo 	MFP2->mf_imrb |= IB_DCHG;
    358  1.1  leo 	MFP2->mf_aer  |= 0x10; /* fdc int low->high */
    359  1.1  leo 
    360  1.1  leo 	/* physical limit: four drives per controller. */
    361  1.1  leo 	for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
    362  1.1  leo 		/*
    363  1.1  leo 		 * XXX: Choose something sensible as a default...
    364  1.1  leo 		 */
    365  1.1  leo 		fa.fa_deftype = &fd_types[2]; /* 1.44MB */
    366  1.1  leo 		(void)config_found(self, (void *)&fa, fdprint);
    367  1.1  leo 	}
    368  1.1  leo }
    369  1.1  leo 
    370  1.1  leo int
    371  1.1  leo fdprobe(parent, match, aux)
    372  1.1  leo 	struct device *parent;
    373  1.1  leo 	void *match, *aux;
    374  1.1  leo {
    375  1.1  leo 	struct fdc_softc	*fdc = (void *)parent;
    376  1.1  leo 	struct cfdata		*cf = match;
    377  1.1  leo 	struct fdc_attach_args	*fa = aux;
    378  1.1  leo 	int			drive = fa->fa_drive;
    379  1.1  leo 	int			n;
    380  1.1  leo 
    381  1.1  leo 	if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != drive)
    382  1.1  leo 		return 0;
    383  1.1  leo 	/*
    384  1.1  leo 	 * XXX
    385  1.1  leo 	 * This is to work around some odd interactions between this driver
    386  1.1  leo 	 * and SMC Ethernet cards.
    387  1.1  leo 	 */
    388  1.1  leo 	if (cf->cf_loc[0] == -1 && drive >= 2)
    389  1.1  leo 		return 0;
    390  1.1  leo 
    391  1.1  leo 	/* select drive and turn on motor */
    392  1.1  leo 	wrt_fdc_reg(fdout, drive | FDO_FRST | FDO_MOEN(drive));
    393  1.1  leo 
    394  1.1  leo 	/* wait for motor to spin up */
    395  1.1  leo 	delay(250000);
    396  1.1  leo 	out_fdc(NE7CMD_RECAL);
    397  1.1  leo 	out_fdc(drive);
    398  1.1  leo 
    399  1.1  leo 	/* wait for recalibrate */
    400  1.1  leo 	delay(2000000);
    401  1.1  leo 	out_fdc(NE7CMD_SENSEI);
    402  1.1  leo 	n = fdcresult(fdc);
    403  1.1  leo 
    404  1.1  leo #ifdef FD_DEBUG
    405  1.1  leo 	{
    406  1.1  leo 		int i;
    407  1.1  leo 		printf("fdprobe: status");
    408  1.1  leo 		for (i = 0; i < n; i++)
    409  1.1  leo 			printf(" %x", fdc->sc_status[i]);
    410  1.1  leo 		printf("\n");
    411  1.1  leo 	}
    412  1.1  leo #endif
    413  1.1  leo 	intr_arg = (void*)fdc;
    414  1.1  leo 	if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20)
    415  1.1  leo 		return 0;
    416  1.1  leo 	/* turn off motor */
    417  1.1  leo 	wrt_fdc_reg(fdout, FDO_FRST);
    418  1.1  leo 
    419  1.1  leo 	return 1;
    420  1.1  leo }
    421  1.1  leo 
    422  1.1  leo /*
    423  1.1  leo  * Controller is working, and drive responded.  Attach it.
    424  1.1  leo  */
    425  1.1  leo void
    426  1.1  leo fdattach(parent, self, aux)
    427  1.1  leo 	struct device *parent, *self;
    428  1.1  leo 	void *aux;
    429  1.1  leo {
    430  1.1  leo 	struct fdc_softc	*fdc  = (void *)parent;
    431  1.1  leo 	struct fd_softc		*fd   = (void *)self;
    432  1.1  leo 	struct fdc_attach_args	*fa   = aux;
    433  1.1  leo 	struct fd_type		*type = fa->fa_deftype;
    434  1.1  leo 	int			drive = fa->fa_drive;
    435  1.1  leo 
    436  1.1  leo 	/* XXX Allow `flags' to override device type? */
    437  1.1  leo 
    438  1.1  leo 	if (type)
    439  1.1  leo 		printf(": %s %d cyl, %d head, %d sec\n", type->name,
    440  1.1  leo 		    type->tracks, type->heads, type->sectrac);
    441  1.1  leo 	else
    442  1.1  leo 		printf(": density unknown\n");
    443  1.1  leo 
    444  1.1  leo 	fd->sc_cylin      = -1;
    445  1.1  leo 	fd->sc_drive      = drive;
    446  1.1  leo 	fd->sc_deftype    = type;
    447  1.1  leo 	fdc->sc_fd[drive] = fd;
    448  1.1  leo 
    449  1.1  leo 	/*
    450  1.1  leo 	 * Initialize and attach the disk structure.
    451  1.1  leo 	 */
    452  1.1  leo 	fd->sc_dk.dk_name   = fd->sc_dev.dv_xname;
    453  1.1  leo 	fd->sc_dk.dk_driver = &fddkdriver;
    454  1.1  leo 	disk_attach(&fd->sc_dk);
    455  1.1  leo 
    456  1.1  leo 	/* XXX Need to do some more fiddling with sc_dk. */
    457  1.1  leo 	dk_establish(&fd->sc_dk, &fd->sc_dev);
    458  1.1  leo 
    459  1.1  leo 	/* Needed to power off if the motor is on when we halt. */
    460  1.1  leo 	fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd);
    461  1.1  leo }
    462  1.1  leo 
    463  1.1  leo /*
    464  1.1  leo  * This is called from the assembly part of the interrupt handler
    465  1.1  leo  * when it is clear that the interrupt was not related to shoving
    466  1.1  leo  * data.
    467  1.1  leo  */
    468  1.1  leo void
    469  1.1  leo fdc_ctrl_intr(frame)
    470  1.1  leo 	register struct clockframe *frame;
    471  1.1  leo {
    472  1.1  leo 	int	s;
    473  1.1  leo 
    474  1.1  leo 	/*
    475  1.1  leo 	 * Disable further interrupts. The fdcintr() routine
    476  1.1  leo 	 * explicitely enables them when needed.
    477  1.1  leo 	 */
    478  1.1  leo 	MFP2->mf_ierb &= ~IB_DCHG;
    479  1.1  leo 
    480  1.1  leo 	/*
    481  1.1  leo 	 * Set fddmalen to zero so no pseudo-dma transfers will
    482  1.1  leo 	 * occur.
    483  1.1  leo 	 */
    484  1.1  leo 	fddmalen = 0;
    485  1.1  leo 
    486  1.1  leo 	if (!BASEPRI(frame->sr)) {
    487  1.1  leo 		/*
    488  1.1  leo 		 * We don't want to stay on ipl6.....
    489  1.1  leo 		 */
    490  1.1  leo 		add_sicallback((si_farg)fdcpseudointr, intr_arg, 0);
    491  1.1  leo 	}
    492  1.1  leo 	else {
    493  1.1  leo 		s = splbio();
    494  1.1  leo 		(void) fdcintr(intr_arg);
    495  1.1  leo 		splx(s);
    496  1.1  leo 	}
    497  1.1  leo }
    498  1.1  leo 
    499  1.1  leo __inline struct fd_type *
    500  1.1  leo fd_dev_to_type(fd, dev)
    501  1.1  leo 	struct fd_softc *fd;
    502  1.1  leo 	dev_t dev;
    503  1.1  leo {
    504  1.1  leo 	int type = FDTYPE(dev);
    505  1.1  leo 
    506  1.1  leo 	if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
    507  1.1  leo 		return NULL;
    508  1.1  leo 	return type ? &fd_types[type - 1] : fd->sc_deftype;
    509  1.1  leo }
    510  1.1  leo 
    511  1.1  leo void
    512  1.1  leo fdstrategy(bp)
    513  1.1  leo 	register struct buf *bp;	/* IO operation to perform */
    514  1.1  leo {
    515  1.1  leo 	struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(bp->b_dev)];
    516  1.1  leo 	int sz;
    517  1.1  leo  	int s;
    518  1.1  leo 
    519  1.1  leo 	/* Valid unit, controller, and request? */
    520  1.1  leo 	if (bp->b_blkno < 0 ||
    521  1.1  leo 	    (bp->b_bcount % FDC_BSIZE) != 0) {
    522  1.1  leo 		bp->b_error = EINVAL;
    523  1.1  leo 		goto bad;
    524  1.1  leo 	}
    525  1.1  leo 
    526  1.1  leo 	/* If it's a null transfer, return immediately. */
    527  1.1  leo 	if (bp->b_bcount == 0)
    528  1.1  leo 		goto done;
    529  1.1  leo 
    530  1.1  leo 	sz = howmany(bp->b_bcount, FDC_BSIZE);
    531  1.1  leo 
    532  1.1  leo 	if (bp->b_blkno + sz > fd->sc_type->size) {
    533  1.1  leo 		sz = fd->sc_type->size - bp->b_blkno;
    534  1.1  leo 		if (sz == 0) {
    535  1.1  leo 			/* If exactly at end of disk, return EOF. */
    536  1.1  leo 			goto done;
    537  1.1  leo 		}
    538  1.1  leo 		if (sz < 0) {
    539  1.1  leo 			/* If past end of disk, return EINVAL. */
    540  1.1  leo 			bp->b_error = EINVAL;
    541  1.1  leo 			goto bad;
    542  1.1  leo 		}
    543  1.1  leo 		/* Otherwise, truncate request. */
    544  1.1  leo 		bp->b_bcount = sz << DEV_BSHIFT;
    545  1.1  leo 	}
    546  1.1  leo 
    547  1.1  leo  	bp->b_cylin = bp->b_blkno / (FDC_BSIZE/DEV_BSIZE) / fd->sc_type->seccyl;
    548  1.1  leo 
    549  1.1  leo #ifdef FD_DEBUG
    550  1.1  leo 	printf("fdstrategy: b_blkno %d b_bcount %ld blkno %ld cylin %ld sz"
    551  1.1  leo 		" %d\n", bp->b_blkno, bp->b_bcount, (long)fd->sc_blkno,
    552  1.1  leo 		bp->b_cylin, sz);
    553  1.1  leo #endif
    554  1.1  leo 
    555  1.1  leo 	/* Queue transfer on drive, activate drive and controller if idle. */
    556  1.1  leo 	s = splbio();
    557  1.1  leo 	disksort(&fd->sc_q, bp);
    558  1.1  leo 	untimeout(fd_motor_off, fd); /* a good idea */
    559  1.1  leo 	if (!fd->sc_q.b_active)
    560  1.1  leo 		fdstart(fd);
    561  1.1  leo #ifdef DIAGNOSTIC
    562  1.1  leo 	else {
    563  1.1  leo 		struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    564  1.1  leo 		if (fdc->sc_state == DEVIDLE) {
    565  1.1  leo 			printf("fdstrategy: controller inactive\n");
    566  1.1  leo 			fdcstart(fdc);
    567  1.1  leo 		}
    568  1.1  leo 	}
    569  1.1  leo #endif
    570  1.1  leo 	splx(s);
    571  1.1  leo 	return;
    572  1.1  leo 
    573  1.1  leo bad:
    574  1.1  leo 	bp->b_flags |= B_ERROR;
    575  1.1  leo done:
    576  1.1  leo 	/* Toss transfer; we're done early. */
    577  1.1  leo 	bp->b_resid = bp->b_bcount;
    578  1.1  leo 	biodone(bp);
    579  1.1  leo }
    580  1.1  leo 
    581  1.1  leo void
    582  1.1  leo fdstart(fd)
    583  1.1  leo 	struct fd_softc *fd;
    584  1.1  leo {
    585  1.1  leo 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    586  1.1  leo 	int active = fdc->sc_drives.tqh_first != 0;
    587  1.1  leo 
    588  1.1  leo 	/* Link into controller queue. */
    589  1.1  leo 	fd->sc_q.b_active = 1;
    590  1.1  leo 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    591  1.1  leo 
    592  1.1  leo 	/* If controller not already active, start it. */
    593  1.1  leo 	if (!active)
    594  1.1  leo 		fdcstart(fdc);
    595  1.1  leo }
    596  1.1  leo 
    597  1.1  leo void
    598  1.1  leo fdfinish(fd, bp)
    599  1.1  leo 	struct fd_softc *fd;
    600  1.1  leo 	struct buf *bp;
    601  1.1  leo {
    602  1.1  leo 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    603  1.1  leo 
    604  1.1  leo 	/*
    605  1.1  leo 	 * Move this drive to the end of the queue to give others a `fair'
    606  1.1  leo 	 * chance.  We only force a switch if N operations are completed while
    607  1.1  leo 	 * another drive is waiting to be serviced, since there is a long motor
    608  1.1  leo 	 * startup delay whenever we switch.
    609  1.1  leo 	 */
    610  1.1  leo 	if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
    611  1.1  leo 		fd->sc_ops = 0;
    612  1.1  leo 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
    613  1.1  leo 		if (bp->b_actf) {
    614  1.1  leo 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    615  1.1  leo 		} else
    616  1.1  leo 			fd->sc_q.b_active = 0;
    617  1.1  leo 	}
    618  1.1  leo 	bp->b_resid = fd->sc_bcount;
    619  1.1  leo 	fd->sc_skip = 0;
    620  1.1  leo 	fd->sc_q.b_actf = bp->b_actf;
    621  1.1  leo 
    622  1.1  leo 	biodone(bp);
    623  1.1  leo 	/* turn off motor 5s from now */
    624  1.1  leo 	timeout(fd_motor_off, fd, 5 * hz);
    625  1.1  leo 	fdc->sc_state = DEVIDLE;
    626  1.1  leo }
    627  1.1  leo 
    628  1.1  leo int
    629  1.1  leo fdread(dev, uio, flags)
    630  1.1  leo 	dev_t dev;
    631  1.1  leo 	struct uio *uio;
    632  1.1  leo 	int flags;
    633  1.1  leo {
    634  1.1  leo 	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
    635  1.1  leo }
    636  1.1  leo 
    637  1.1  leo int
    638  1.1  leo fdwrite(dev, uio, flags)
    639  1.1  leo 	dev_t dev;
    640  1.1  leo 	struct uio *uio;
    641  1.1  leo 	int flags;
    642  1.1  leo {
    643  1.1  leo 	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
    644  1.1  leo }
    645  1.1  leo 
    646  1.1  leo void
    647  1.1  leo fd_set_motor(fdc, reset)
    648  1.1  leo 	struct fdc_softc *fdc;
    649  1.1  leo 	int reset;
    650  1.1  leo {
    651  1.1  leo 	struct fd_softc *fd;
    652  1.1  leo 	u_char status;
    653  1.1  leo 	int n;
    654  1.1  leo 
    655  1.1  leo 	if ((fd = fdc->sc_drives.tqh_first) != NULL)
    656  1.1  leo 		status = fd->sc_drive;
    657  1.1  leo 	else
    658  1.1  leo 		status = 0;
    659  1.1  leo 	if (!reset)
    660  1.1  leo 		status |= FDO_FRST | FDO_FDMAEN;
    661  1.1  leo 	for (n = 0; n < 4; n++)
    662  1.1  leo 		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
    663  1.1  leo 			status |= FDO_MOEN(n);
    664  1.1  leo 	wrt_fdc_reg(fdout, status);
    665  1.1  leo }
    666  1.1  leo 
    667  1.1  leo void
    668  1.1  leo fd_motor_off(arg)
    669  1.1  leo 	void *arg;
    670  1.1  leo {
    671  1.1  leo 	struct fd_softc *fd = arg;
    672  1.1  leo 	int s;
    673  1.1  leo 
    674  1.1  leo 	s = splbio();
    675  1.1  leo 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
    676  1.1  leo 	fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0);
    677  1.1  leo 	splx(s);
    678  1.1  leo }
    679  1.1  leo 
    680  1.1  leo void
    681  1.1  leo fd_motor_on(arg)
    682  1.1  leo 	void *arg;
    683  1.1  leo {
    684  1.1  leo 	struct fd_softc *fd = arg;
    685  1.1  leo 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    686  1.1  leo 	int s;
    687  1.1  leo 
    688  1.1  leo 	s = splbio();
    689  1.1  leo 	fd->sc_flags &= ~FD_MOTOR_WAIT;
    690  1.1  leo 	if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
    691  1.1  leo 		(void) fdcintr(fdc);
    692  1.1  leo 	splx(s);
    693  1.1  leo }
    694  1.1  leo 
    695  1.1  leo int
    696  1.1  leo fdcresult(fdc)
    697  1.1  leo 	struct fdc_softc *fdc;
    698  1.1  leo {
    699  1.1  leo 	u_char i;
    700  1.1  leo 	int j = 100000,
    701  1.1  leo 	    n = 0;
    702  1.1  leo 
    703  1.1  leo 	for (; j; j--) {
    704  1.1  leo 		i = rd_fdc_reg(fdsts) & (NE7_DIO | NE7_RQM | NE7_CB);
    705  1.1  leo 		if (i == NE7_RQM)
    706  1.1  leo 			return n;
    707  1.1  leo 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
    708  1.1  leo 			if (n >= sizeof(fdc->sc_status)) {
    709  1.1  leo 				log(LOG_ERR, "fdcresult: overrun\n");
    710  1.1  leo 				return -1;
    711  1.1  leo 			}
    712  1.1  leo 			fdc->sc_status[n++] = rd_fdc_reg(fddata);
    713  1.1  leo 		}
    714  1.1  leo 	}
    715  1.1  leo 	log(LOG_ERR, "fdcresult: timeout\n");
    716  1.1  leo 	return -1;
    717  1.1  leo }
    718  1.1  leo 
    719  1.1  leo int
    720  1.1  leo out_fdc(x)
    721  1.1  leo 	u_char x;
    722  1.1  leo {
    723  1.1  leo 	int i = 100000;
    724  1.1  leo 
    725  1.1  leo 	while ((rd_fdc_reg(fdsts) & NE7_RQM) == 0 && i-- > 0);
    726  1.1  leo 	if (i <= 0)
    727  1.1  leo 		return -1;
    728  1.1  leo 	while ((rd_fdc_reg(fdsts) & NE7_DIO) && i-- > 0);
    729  1.1  leo 	if (i <= 0)
    730  1.1  leo 		return -1;
    731  1.1  leo 	wrt_fdc_reg(fddata, x);
    732  1.1  leo 	return 0;
    733  1.1  leo }
    734  1.1  leo 
    735  1.1  leo int
    736  1.1  leo fdopen(dev, flags, mode, p)
    737  1.1  leo 	dev_t dev;
    738  1.1  leo 	int flags;
    739  1.1  leo 	int mode;
    740  1.1  leo 	struct proc *p;
    741  1.1  leo {
    742  1.1  leo  	int unit;
    743  1.1  leo 	struct fd_softc *fd;
    744  1.1  leo 	struct fd_type *type;
    745  1.1  leo 
    746  1.1  leo 	unit = FDUNIT(dev);
    747  1.1  leo 	if (unit >= hdfd_cd.cd_ndevs)
    748  1.1  leo 		return ENXIO;
    749  1.1  leo 	fd = hdfd_cd.cd_devs[unit];
    750  1.1  leo 	if (fd == 0)
    751  1.1  leo 		return ENXIO;
    752  1.1  leo 	type = fd_dev_to_type(fd, dev);
    753  1.1  leo 	if (type == NULL)
    754  1.1  leo 		return ENXIO;
    755  1.1  leo 
    756  1.1  leo 	if ((fd->sc_flags & FD_OPEN) != 0 &&
    757  1.1  leo 	    fd->sc_type != type)
    758  1.1  leo 		return EBUSY;
    759  1.1  leo 
    760  1.1  leo 	fd->sc_type = type;
    761  1.1  leo 	fd->sc_cylin = -1;
    762  1.1  leo 	fd->sc_flags |= FD_OPEN;
    763  1.1  leo 
    764  1.1  leo 	return 0;
    765  1.1  leo }
    766  1.1  leo 
    767  1.1  leo int
    768  1.1  leo fdclose(dev, flags, mode, p)
    769  1.1  leo 	dev_t dev;
    770  1.1  leo 	int flags;
    771  1.1  leo 	int mode;
    772  1.1  leo 	struct proc *p;
    773  1.1  leo {
    774  1.1  leo 	struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(dev)];
    775  1.1  leo 
    776  1.1  leo 	fd->sc_flags &= ~FD_OPEN;
    777  1.1  leo 	return 0;
    778  1.1  leo }
    779  1.1  leo 
    780  1.1  leo void
    781  1.1  leo fdcstart(fdc)
    782  1.1  leo 	struct fdc_softc *fdc;
    783  1.1  leo {
    784  1.1  leo 
    785  1.1  leo #ifdef DIAGNOSTIC
    786  1.1  leo 	/* only got here if controller's drive queue was inactive; should
    787  1.1  leo 	   be in idle state */
    788  1.1  leo 	if (fdc->sc_state != DEVIDLE) {
    789  1.1  leo 		printf("fdcstart: not idle\n");
    790  1.1  leo 		return;
    791  1.1  leo 	}
    792  1.1  leo #endif
    793  1.1  leo 	(void) fdcintr(fdc);
    794  1.1  leo }
    795  1.1  leo 
    796  1.1  leo void
    797  1.1  leo fdcstatus(dv, n, s)
    798  1.1  leo 	struct device *dv;
    799  1.1  leo 	int n;
    800  1.1  leo 	char *s;
    801  1.1  leo {
    802  1.1  leo 	struct fdc_softc *fdc = (void *)dv->dv_parent;
    803  1.1  leo 
    804  1.1  leo 	if (n == 0) {
    805  1.1  leo 		out_fdc(NE7CMD_SENSEI);
    806  1.1  leo 		(void) fdcresult(fdc);
    807  1.1  leo 		n = 2;
    808  1.1  leo 	}
    809  1.1  leo 
    810  1.1  leo 	printf("%s: %s", dv->dv_xname, s);
    811  1.1  leo 
    812  1.1  leo 	switch (n) {
    813  1.1  leo 	case 0:
    814  1.1  leo 		printf("\n");
    815  1.1  leo 		break;
    816  1.1  leo 	case 2:
    817  1.1  leo 		printf(" (st0 %b cyl %d)\n",
    818  1.1  leo 		    fdc->sc_status[0], NE7_ST0BITS,
    819  1.1  leo 		    fdc->sc_status[1]);
    820  1.1  leo 		break;
    821  1.1  leo 	case 7:
    822  1.1  leo 		printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n",
    823  1.1  leo 		    fdc->sc_status[0], NE7_ST0BITS,
    824  1.1  leo 		    fdc->sc_status[1], NE7_ST1BITS,
    825  1.1  leo 		    fdc->sc_status[2], NE7_ST2BITS,
    826  1.1  leo 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
    827  1.1  leo 		break;
    828  1.1  leo #ifdef DIAGNOSTIC
    829  1.1  leo 	default:
    830  1.1  leo 		printf("\nfdcstatus: weird size");
    831  1.1  leo 		break;
    832  1.1  leo #endif
    833  1.1  leo 	}
    834  1.1  leo }
    835  1.1  leo 
    836  1.1  leo void
    837  1.1  leo fdctimeout(arg)
    838  1.1  leo 	void *arg;
    839  1.1  leo {
    840  1.1  leo 	struct fdc_softc *fdc = arg;
    841  1.1  leo 	struct fd_softc *fd = fdc->sc_drives.tqh_first;
    842  1.1  leo 	int s;
    843  1.1  leo 
    844  1.1  leo 	s = splbio();
    845  1.1  leo 	fdcstatus(&fd->sc_dev, 0, "timeout");
    846  1.1  leo 
    847  1.1  leo 	if (fd->sc_q.b_actf)
    848  1.1  leo 		fdc->sc_state++;
    849  1.1  leo 	else
    850  1.1  leo 		fdc->sc_state = DEVIDLE;
    851  1.1  leo 
    852  1.1  leo 	(void) fdcintr(fdc);
    853  1.1  leo 	splx(s);
    854  1.1  leo }
    855  1.1  leo 
    856  1.1  leo void
    857  1.1  leo fdcpseudointr(arg)
    858  1.1  leo 	void *arg;
    859  1.1  leo {
    860  1.1  leo 	int s;
    861  1.1  leo 
    862  1.1  leo 	/* Just ensure it has the right spl. */
    863  1.1  leo 	s = splbio();
    864  1.1  leo 	(void) fdcintr(arg);
    865  1.1  leo 	splx(s);
    866  1.1  leo }
    867  1.1  leo 
    868  1.1  leo int
    869  1.1  leo fdcintr(arg)
    870  1.1  leo 	void *arg;
    871  1.1  leo {
    872  1.1  leo 	struct fdc_softc *fdc = arg;
    873  1.1  leo #define	st0	fdc->sc_status[0]
    874  1.1  leo #define	st1	fdc->sc_status[1]
    875  1.1  leo #define	cyl	fdc->sc_status[1]
    876  1.1  leo 	struct fd_softc	*fd;
    877  1.1  leo 	struct buf	*bp;
    878  1.1  leo 	int		read, head, sec, i, nblks;
    879  1.1  leo 	struct fd_type	*type;
    880  1.1  leo 
    881  1.1  leo loop:
    882  1.1  leo 	/* Is there a drive for the controller to do a transfer with? */
    883  1.1  leo 	fd = fdc->sc_drives.tqh_first;
    884  1.1  leo 	if (fd == NULL) {
    885  1.1  leo 		fdc->sc_state = DEVIDLE;
    886  1.1  leo  		return 1;
    887  1.1  leo 	}
    888  1.1  leo 
    889  1.1  leo 	/* Is there a transfer to this drive?  If not, deactivate drive. */
    890  1.1  leo 	bp = fd->sc_q.b_actf;
    891  1.1  leo 	if (bp == NULL) {
    892  1.1  leo 		fd->sc_ops = 0;
    893  1.1  leo 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
    894  1.1  leo 		fd->sc_q.b_active = 0;
    895  1.1  leo 		goto loop;
    896  1.1  leo 	}
    897  1.1  leo 
    898  1.1  leo 	switch (fdc->sc_state) {
    899  1.1  leo 	case DEVIDLE:
    900  1.1  leo 		fdc->sc_errors = 0;
    901  1.1  leo 		fdc->sc_overruns = 0;
    902  1.1  leo 		fd->sc_skip = 0;
    903  1.1  leo 		fd->sc_bcount = bp->b_bcount;
    904  1.1  leo 		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
    905  1.1  leo 		untimeout(fd_motor_off, fd);
    906  1.1  leo 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
    907  1.1  leo 			fdc->sc_state = MOTORWAIT;
    908  1.1  leo 			return 1;
    909  1.1  leo 		}
    910  1.1  leo 		if ((fd->sc_flags & FD_MOTOR) == 0) {
    911  1.1  leo 			/* Turn on the motor, being careful about pairing. */
    912  1.1  leo 			struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
    913  1.1  leo 			if (ofd && ofd->sc_flags & FD_MOTOR) {
    914  1.1  leo 				untimeout(fd_motor_off, ofd);
    915  1.1  leo 				ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
    916  1.1  leo 			}
    917  1.1  leo 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
    918  1.1  leo 			fd_set_motor(fdc, 0);
    919  1.1  leo 			fdc->sc_state = MOTORWAIT;
    920  1.1  leo 			/* Allow .25s for motor to stabilize. */
    921  1.1  leo 			timeout(fd_motor_on, fd, hz / 4);
    922  1.1  leo 			return 1;
    923  1.1  leo 		}
    924  1.1  leo 		/* Make sure the right drive is selected. */
    925  1.1  leo 		fd_set_motor(fdc, 0);
    926  1.1  leo 
    927  1.1  leo 		/* fall through */
    928  1.1  leo 	case DOSEEK:
    929  1.1  leo 	doseek:
    930  1.1  leo 		if (fd->sc_cylin == bp->b_cylin)
    931  1.1  leo 			goto doio;
    932  1.1  leo 
    933  1.1  leo 		out_fdc(NE7CMD_SPECIFY);/* specify command */
    934  1.1  leo 		out_fdc(fd->sc_type->steprate);
    935  1.1  leo 		out_fdc(0x7);	/* XXX head load time == 6ms - non-dma */
    936  1.1  leo 
    937  1.1  leo 		fdc_ienable();
    938  1.1  leo 
    939  1.1  leo 		out_fdc(NE7CMD_SEEK);	/* seek function */
    940  1.1  leo 		out_fdc(fd->sc_drive);	/* drive number */
    941  1.1  leo 		out_fdc(bp->b_cylin * fd->sc_type->step);
    942  1.1  leo 
    943  1.1  leo 		fd->sc_cylin = -1;
    944  1.1  leo 		fdc->sc_state = SEEKWAIT;
    945  1.1  leo 
    946  1.1  leo 		fd->sc_dk.dk_seek++;
    947  1.1  leo 		disk_busy(&fd->sc_dk);
    948  1.1  leo 
    949  1.1  leo 		timeout(fdctimeout, fdc, 4 * hz);
    950  1.1  leo 		return 1;
    951  1.1  leo 
    952  1.1  leo 	case DOIO:
    953  1.1  leo 	doio:
    954  1.1  leo 		type  = fd->sc_type;
    955  1.1  leo 		sec   = fd->sc_blkno % type->seccyl;
    956  1.1  leo 		head  = sec / type->sectrac;
    957  1.1  leo 		sec  -= head * type->sectrac;
    958  1.1  leo 		nblks = type->sectrac - sec;
    959  1.1  leo 		nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
    960  1.1  leo 		nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
    961  1.1  leo 		fd->sc_nblks  = nblks;
    962  1.1  leo 		fd->sc_nbytes = nblks * FDC_BSIZE;
    963  1.1  leo #ifdef DIAGNOSTIC
    964  1.1  leo 		{
    965  1.1  leo 		     int block;
    966  1.1  leo 
    967  1.1  leo 		     block = (fd->sc_cylin * type->heads + head)
    968  1.1  leo 				* type->sectrac + sec;
    969  1.1  leo 		     if (block != fd->sc_blkno) {
    970  1.1  leo 			 printf("fdcintr: block %d != blkno %d\n",
    971  1.1  leo 						block, fd->sc_blkno);
    972  1.1  leo #ifdef DDB
    973  1.1  leo 			 Debugger();
    974  1.1  leo #endif
    975  1.1  leo 		     }
    976  1.1  leo 		}
    977  1.1  leo #endif
    978  1.1  leo 		read = bp->b_flags & B_READ ? 1 : 0;
    979  1.1  leo 
    980  1.1  leo 		/*
    981  1.1  leo 		 * Setup pseudo-dma address & count
    982  1.1  leo 		 */
    983  1.1  leo 		fddmaaddr = bp->b_data + fd->sc_skip;
    984  1.1  leo 		fddmalen  = fd->sc_nbytes;
    985  1.1  leo 
    986  1.1  leo 		wrt_fdc_reg(fdctl, type->rate);
    987  1.1  leo #ifdef FD_DEBUG
    988  1.1  leo 		printf("fdcintr: %s drive %d track %d head %d sec %d"
    989  1.1  leo 			" nblks %d\n", read ? "read" : "write",
    990  1.1  leo 			fd->sc_drive, fd->sc_cylin, head, sec, nblks);
    991  1.1  leo #endif
    992  1.1  leo 		fdc_ienable();
    993  1.1  leo 
    994  1.1  leo 		if (read)
    995  1.1  leo 			out_fdc(NE7CMD_READ);	/* READ */
    996  1.1  leo 		else
    997  1.1  leo 			out_fdc(NE7CMD_WRITE);	/* WRITE */
    998  1.1  leo 		out_fdc((head << 2) | fd->sc_drive);
    999  1.1  leo 		out_fdc(fd->sc_cylin);		/* track	 */
   1000  1.1  leo 		out_fdc(head);			/* head		 */
   1001  1.1  leo 		out_fdc(sec + 1);		/* sector +1	 */
   1002  1.1  leo 		out_fdc(type->secsize);	/* sector size   */
   1003  1.1  leo 		out_fdc(sec + nblks);		/* last sectors	 */
   1004  1.1  leo 		out_fdc(type->gap1);		/* gap1 size	 */
   1005  1.1  leo 		out_fdc(type->datalen);	/* data length	 */
   1006  1.1  leo 		fdc->sc_state = IOCOMPLETE;
   1007  1.1  leo 
   1008  1.1  leo 		disk_busy(&fd->sc_dk);
   1009  1.1  leo 
   1010  1.1  leo 		/* allow 2 seconds for operation */
   1011  1.1  leo 		timeout(fdctimeout, fdc, 2 * hz);
   1012  1.1  leo 		return 1;				/* will return later */
   1013  1.1  leo 
   1014  1.1  leo 	case SEEKWAIT:
   1015  1.1  leo 		untimeout(fdctimeout, fdc);
   1016  1.1  leo 		fdc->sc_state = SEEKCOMPLETE;
   1017  1.1  leo 		/* allow 1/50 second for heads to settle */
   1018  1.1  leo 		timeout(fdcpseudointr, fdc, hz / 50);
   1019  1.1  leo 		return 1;
   1020  1.1  leo 
   1021  1.1  leo 	case SEEKCOMPLETE:
   1022  1.1  leo 		disk_unbusy(&fd->sc_dk, 0);	/* no data on seek */
   1023  1.1  leo 
   1024  1.1  leo 		/* Make sure seek really happened. */
   1025  1.1  leo 		out_fdc(NE7CMD_SENSEI);
   1026  1.1  leo 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
   1027  1.1  leo 		    cyl != bp->b_cylin * fd->sc_type->step) {
   1028  1.1  leo #ifdef FD_DEBUG
   1029  1.1  leo 			fdcstatus(&fd->sc_dev, 2, "seek failed");
   1030  1.1  leo #endif
   1031  1.1  leo 			fdcretry(fdc);
   1032  1.1  leo 			goto loop;
   1033  1.1  leo 		}
   1034  1.1  leo 		fd->sc_cylin = bp->b_cylin;
   1035  1.1  leo 		goto doio;
   1036  1.1  leo 
   1037  1.1  leo 	case IOTIMEDOUT:
   1038  1.1  leo 	case SEEKTIMEDOUT:
   1039  1.1  leo 	case RECALTIMEDOUT:
   1040  1.1  leo 	case RESETTIMEDOUT:
   1041  1.1  leo 		fdcretry(fdc);
   1042  1.1  leo 		goto loop;
   1043  1.1  leo 
   1044  1.1  leo 	case IOCOMPLETE: /* IO DONE, post-analyze */
   1045  1.1  leo 		untimeout(fdctimeout, fdc);
   1046  1.1  leo 
   1047  1.1  leo 		disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid));
   1048  1.1  leo 
   1049  1.1  leo 		if (fdcresult(fdc) != 7 || (st1 & 0x37) != 0) {
   1050  1.1  leo 			/*
   1051  1.1  leo 			 * As the damn chip doesn't seem to have a FIFO,
   1052  1.1  leo 			 * accept a few overruns as a fact of life *sigh*
   1053  1.1  leo 			 */
   1054  1.1  leo 			if ((st1 & 0x10) && (++fdc->sc_overruns < 4)) {
   1055  1.1  leo 				fdc->sc_state = DOSEEK;
   1056  1.1  leo 				goto loop;
   1057  1.1  leo 			}
   1058  1.1  leo #ifdef FD_DEBUG
   1059  1.1  leo 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
   1060  1.1  leo 			    "read failed" : "write failed");
   1061  1.1  leo 			printf("blkno %d nblks %d\n",
   1062  1.1  leo 			    fd->sc_blkno, fd->sc_nblks);
   1063  1.1  leo #endif
   1064  1.1  leo 			fdcretry(fdc);
   1065  1.1  leo 			goto loop;
   1066  1.1  leo 		}
   1067  1.1  leo 		if (fdc->sc_errors) {
   1068  1.1  leo 			diskerr(bp, "fd", "soft error", LOG_PRINTF,
   1069  1.1  leo 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
   1070  1.1  leo 			printf("\n");
   1071  1.1  leo 			fdc->sc_errors = 0;
   1072  1.1  leo 		}
   1073  1.1  leo 		fdc->sc_overruns = 0;
   1074  1.1  leo 		fd->sc_blkno += fd->sc_nblks;
   1075  1.1  leo 		fd->sc_skip += fd->sc_nbytes;
   1076  1.1  leo 		fd->sc_bcount -= fd->sc_nbytes;
   1077  1.1  leo 		if (fd->sc_bcount > 0) {
   1078  1.1  leo 			bp->b_cylin = fd->sc_blkno / fd->sc_type->seccyl;
   1079  1.1  leo 			goto doseek;
   1080  1.1  leo 		}
   1081  1.1  leo 		fdfinish(fd, bp);
   1082  1.1  leo 		goto loop;
   1083  1.1  leo 
   1084  1.1  leo 	case DORESET:
   1085  1.1  leo 		/* try a reset, keep motor on */
   1086  1.1  leo 		fd_set_motor(fdc, 1);
   1087  1.1  leo 		delay(100);
   1088  1.1  leo 		fd_set_motor(fdc, 0);
   1089  1.1  leo 		fdc->sc_state = RESETCOMPLETE;
   1090  1.1  leo 		timeout(fdctimeout, fdc, hz / 2);
   1091  1.1  leo 		return 1;			/* will return later */
   1092  1.1  leo 
   1093  1.1  leo 	case RESETCOMPLETE:
   1094  1.1  leo 		untimeout(fdctimeout, fdc);
   1095  1.1  leo 		/* clear the controller output buffer */
   1096  1.1  leo 		for (i = 0; i < 4; i++) {
   1097  1.1  leo 			out_fdc(NE7CMD_SENSEI);
   1098  1.1  leo 			(void) fdcresult(fdc);
   1099  1.1  leo 		}
   1100  1.1  leo 
   1101  1.1  leo 		/* fall through */
   1102  1.1  leo 	case DORECAL:
   1103  1.1  leo 		fdc_ienable();
   1104  1.1  leo 
   1105  1.1  leo 		out_fdc(NE7CMD_RECAL);	/* recalibrate function */
   1106  1.1  leo 		out_fdc(fd->sc_drive);
   1107  1.1  leo 		fdc->sc_state = RECALWAIT;
   1108  1.1  leo 		timeout(fdctimeout, fdc, 5 * hz);
   1109  1.1  leo 		return 1;			/* will return later */
   1110  1.1  leo 
   1111  1.1  leo 	case RECALWAIT:
   1112  1.1  leo 		untimeout(fdctimeout, fdc);
   1113  1.1  leo 		fdc->sc_state = RECALCOMPLETE;
   1114  1.1  leo 		/* allow 1/30 second for heads to settle */
   1115  1.1  leo 		timeout(fdcpseudointr, fdc, hz / 30);
   1116  1.1  leo 		return 1;			/* will return later */
   1117  1.1  leo 
   1118  1.1  leo 	case RECALCOMPLETE:
   1119  1.1  leo 		out_fdc(NE7CMD_SENSEI);
   1120  1.1  leo 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
   1121  1.1  leo #ifdef FD_DEBUG
   1122  1.1  leo 			fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
   1123  1.1  leo #endif
   1124  1.1  leo 			fdcretry(fdc);
   1125  1.1  leo 			goto loop;
   1126  1.1  leo 		}
   1127  1.1  leo 		fd->sc_cylin = 0;
   1128  1.1  leo 		goto doseek;
   1129  1.1  leo 
   1130  1.1  leo 	case MOTORWAIT:
   1131  1.1  leo 		if (fd->sc_flags & FD_MOTOR_WAIT)
   1132  1.1  leo 			return 1;		/* time's not up yet */
   1133  1.1  leo 		goto doseek;
   1134  1.1  leo 
   1135  1.1  leo 	default:
   1136  1.1  leo 		fdcstatus(&fd->sc_dev, 0, "stray interrupt");
   1137  1.1  leo 		return 1;
   1138  1.1  leo 	}
   1139  1.1  leo #ifdef DIAGNOSTIC
   1140  1.1  leo 	panic("fdcintr: impossible");
   1141  1.1  leo #endif
   1142  1.1  leo #undef	st0
   1143  1.1  leo #undef	st1
   1144  1.1  leo #undef	cyl
   1145  1.1  leo }
   1146  1.1  leo 
   1147  1.1  leo void
   1148  1.1  leo fdcretry(fdc)
   1149  1.1  leo 	struct fdc_softc *fdc;
   1150  1.1  leo {
   1151  1.1  leo 	struct fd_softc *fd;
   1152  1.1  leo 	struct buf *bp;
   1153  1.1  leo 
   1154  1.1  leo 	fd = fdc->sc_drives.tqh_first;
   1155  1.1  leo 	bp = fd->sc_q.b_actf;
   1156  1.1  leo 
   1157  1.1  leo 	switch (fdc->sc_errors) {
   1158  1.1  leo 	case 0:
   1159  1.1  leo 		/* try again */
   1160  1.1  leo 		fdc->sc_state = DOSEEK;
   1161  1.1  leo 		break;
   1162  1.1  leo 
   1163  1.1  leo 	case 1: case 2: case 3:
   1164  1.1  leo 		/* didn't work; try recalibrating */
   1165  1.1  leo 		fdc->sc_state = DORECAL;
   1166  1.1  leo 		break;
   1167  1.1  leo 
   1168  1.1  leo 	case 4:
   1169  1.1  leo 		/* still no go; reset the bastard */
   1170  1.1  leo 		fdc->sc_state = DORESET;
   1171  1.1  leo 		break;
   1172  1.1  leo 
   1173  1.1  leo 	default:
   1174  1.1  leo 		diskerr(bp, "fd", "hard error", LOG_PRINTF,
   1175  1.1  leo 		    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
   1176  1.1  leo 		printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n",
   1177  1.1  leo 		    fdc->sc_status[0], NE7_ST0BITS,
   1178  1.1  leo 		    fdc->sc_status[1], NE7_ST1BITS,
   1179  1.1  leo 		    fdc->sc_status[2], NE7_ST2BITS,
   1180  1.1  leo 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
   1181  1.1  leo 
   1182  1.1  leo 		bp->b_flags |= B_ERROR;
   1183  1.1  leo 		bp->b_error = EIO;
   1184  1.1  leo 		fdfinish(fd, bp);
   1185  1.1  leo 	}
   1186  1.1  leo 	fdc->sc_errors++;
   1187  1.1  leo }
   1188  1.1  leo 
   1189  1.1  leo int
   1190  1.1  leo fdsize(dev)
   1191  1.1  leo 	dev_t dev;
   1192  1.1  leo {
   1193  1.1  leo 
   1194  1.1  leo 	/* Swapping to floppies would not make sense. */
   1195  1.1  leo 	return -1;
   1196  1.1  leo }
   1197  1.1  leo 
   1198  1.1  leo int
   1199  1.1  leo fddump(dev, blkno, va, size)
   1200  1.1  leo 	dev_t dev;
   1201  1.1  leo 	daddr_t blkno;
   1202  1.1  leo 	caddr_t va;
   1203  1.1  leo 	size_t size;
   1204  1.1  leo {
   1205  1.1  leo 
   1206  1.1  leo 	/* Not implemented. */
   1207  1.1  leo 	return ENXIO;
   1208  1.1  leo }
   1209  1.1  leo 
   1210  1.1  leo int
   1211  1.1  leo fdioctl(dev, cmd, addr, flag, p)
   1212  1.1  leo 	dev_t dev;
   1213  1.1  leo 	u_long cmd;
   1214  1.1  leo 	caddr_t addr;
   1215  1.1  leo 	int flag;
   1216  1.1  leo 	struct proc *p;
   1217  1.1  leo {
   1218  1.1  leo 	struct fd_softc		*fd;
   1219  1.1  leo 	struct disklabel	buffer;
   1220  1.1  leo 	struct cpu_disklabel	cpulab;
   1221  1.1  leo 	int error;
   1222  1.1  leo 
   1223  1.1  leo 	fd = hdfd_cd.cd_devs[FDUNIT(dev)];
   1224  1.1  leo 
   1225  1.1  leo 	switch (cmd) {
   1226  1.1  leo 	case DIOCGDINFO:
   1227  1.1  leo 		bzero(&buffer, sizeof(buffer));
   1228  1.1  leo 		bzero(&cpulab, sizeof(cpulab));
   1229  1.1  leo 
   1230  1.1  leo 		buffer.d_secpercyl  = fd->sc_type->seccyl;
   1231  1.1  leo 		buffer.d_type       = DTYPE_FLOPPY;
   1232  1.1  leo 		buffer.d_secsize    = FDC_BSIZE;
   1233  1.1  leo 		buffer.d_secperunit = fd->sc_type->size;
   1234  1.1  leo 
   1235  1.1  leo 		if (readdisklabel(dev, fdstrategy, &buffer, &cpulab) != NULL)
   1236  1.1  leo 			return EINVAL;
   1237  1.1  leo 		*(struct disklabel *)addr = buffer;
   1238  1.1  leo 		return 0;
   1239  1.1  leo 
   1240  1.1  leo 	case DIOCWLABEL:
   1241  1.1  leo 		if ((flag & FWRITE) == 0)
   1242  1.1  leo 			return EBADF;
   1243  1.1  leo 		/* XXX do something */
   1244  1.1  leo 		return 0;
   1245  1.1  leo 
   1246  1.1  leo 	case DIOCWDINFO:
   1247  1.1  leo 		if ((flag & FWRITE) == 0)
   1248  1.1  leo 			return EBADF;
   1249  1.1  leo 
   1250  1.1  leo 		error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
   1251  1.1  leo 		if (error)
   1252  1.1  leo 			return error;
   1253  1.1  leo 
   1254  1.1  leo 		error = writedisklabel(dev, fdstrategy, &buffer, NULL);
   1255  1.1  leo 		return error;
   1256  1.1  leo 
   1257  1.1  leo 	default:
   1258  1.1  leo 		return ENOTTY;
   1259  1.1  leo 	}
   1260  1.1  leo 
   1261  1.1  leo #ifdef DIAGNOSTIC
   1262  1.1  leo 	panic("fdioctl: impossible");
   1263  1.1  leo #endif
   1264  1.1  leo }
   1265