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