Home | History | Annotate | Line # | Download | only in dev
hdfd.c revision 1.28.8.7
      1  1.28.8.7  thorpej /*	$NetBSD: hdfd.c,v 1.28.8.7 2003/01/03 16:41:13 thorpej Exp $	*/
      2  1.28.8.2  nathanw 
      3  1.28.8.2  nathanw /*-
      4  1.28.8.2  nathanw  * Copyright (c) 1996 Leo Weppelman
      5  1.28.8.2  nathanw  * Copyright (c) 1993, 1994, 1995, 1996
      6  1.28.8.2  nathanw  *	Charles M. Hannum.  All rights reserved.
      7  1.28.8.2  nathanw  * Copyright (c) 1990 The Regents of the University of California.
      8  1.28.8.2  nathanw  * All rights reserved.
      9  1.28.8.2  nathanw  *
     10  1.28.8.2  nathanw  * This code is derived from software contributed to Berkeley by
     11  1.28.8.2  nathanw  * Don Ahn.
     12  1.28.8.2  nathanw  *
     13  1.28.8.2  nathanw  * Redistribution and use in source and binary forms, with or without
     14  1.28.8.2  nathanw  * modification, are permitted provided that the following conditions
     15  1.28.8.2  nathanw  * are met:
     16  1.28.8.2  nathanw  * 1. Redistributions of source code must retain the above copyright
     17  1.28.8.2  nathanw  *    notice, this list of conditions and the following disclaimer.
     18  1.28.8.2  nathanw  * 2. Redistributions in binary form must reproduce the above copyright
     19  1.28.8.2  nathanw  *    notice, this list of conditions and the following disclaimer in the
     20  1.28.8.2  nathanw  *    documentation and/or other materials provided with the distribution.
     21  1.28.8.2  nathanw  * 3. All advertising materials mentioning features or use of this software
     22  1.28.8.2  nathanw  *    must display the following acknowledgement:
     23  1.28.8.2  nathanw  *	This product includes software developed by the University of
     24  1.28.8.2  nathanw  *	California, Berkeley and its contributors.
     25  1.28.8.2  nathanw  * 4. Neither the name of the University nor the names of its contributors
     26  1.28.8.2  nathanw  *    may be used to endorse or promote products derived from this software
     27  1.28.8.2  nathanw  *    without specific prior written permission.
     28  1.28.8.2  nathanw  *
     29  1.28.8.2  nathanw  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     30  1.28.8.2  nathanw  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     31  1.28.8.2  nathanw  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     32  1.28.8.2  nathanw  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     33  1.28.8.2  nathanw  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     34  1.28.8.2  nathanw  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     35  1.28.8.2  nathanw  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     36  1.28.8.2  nathanw  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     37  1.28.8.2  nathanw  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     38  1.28.8.2  nathanw  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     39  1.28.8.2  nathanw  * SUCH DAMAGE.
     40  1.28.8.2  nathanw  *
     41  1.28.8.2  nathanw  *	@(#)fd.c	7.4 (Berkeley) 5/25/91
     42  1.28.8.2  nathanw  */
     43  1.28.8.2  nathanw 
     44  1.28.8.2  nathanw /*
     45  1.28.8.2  nathanw  * Floppy formatting facilities merged from FreeBSD fd.c driver:
     46  1.28.8.2  nathanw  *	Id: fd.c,v 1.53 1995/03/12 22:40:56 joerg Exp
     47  1.28.8.2  nathanw  * which carries the same copyright/redistribution notice as shown above with
     48  1.28.8.2  nathanw  * the addition of the following statement before the "Redistribution and
     49  1.28.8.2  nathanw  * use ..." clause:
     50  1.28.8.2  nathanw  *
     51  1.28.8.2  nathanw  * Copyright (c) 1993, 1994 by
     52  1.28.8.2  nathanw  *  jc (at) irbs.UUCP (John Capo)
     53  1.28.8.2  nathanw  *  vak (at) zebub.msk.su (Serge Vakulenko)
     54  1.28.8.2  nathanw  *  ache (at) astral.msk.su (Andrew A. Chernov)
     55  1.28.8.2  nathanw  *
     56  1.28.8.2  nathanw  * Copyright (c) 1993, 1994, 1995 by
     57  1.28.8.2  nathanw  *  joerg_wunsch (at) uriah.sax.de (Joerg Wunsch)
     58  1.28.8.2  nathanw  *  dufault (at) hda.com (Peter Dufault)
     59  1.28.8.2  nathanw  */
     60  1.28.8.2  nathanw 
     61  1.28.8.2  nathanw #include "opt_ddb.h"
     62  1.28.8.2  nathanw 
     63  1.28.8.2  nathanw #include <sys/param.h>
     64  1.28.8.2  nathanw #include <sys/systm.h>
     65  1.28.8.2  nathanw #include <sys/callout.h>
     66  1.28.8.2  nathanw #include <sys/kernel.h>
     67  1.28.8.2  nathanw #include <sys/file.h>
     68  1.28.8.2  nathanw #include <sys/ioctl.h>
     69  1.28.8.2  nathanw #include <sys/device.h>
     70  1.28.8.2  nathanw #include <sys/disklabel.h>
     71  1.28.8.2  nathanw #include <sys/dkstat.h>
     72  1.28.8.2  nathanw #include <sys/disk.h>
     73  1.28.8.2  nathanw #include <sys/buf.h>
     74  1.28.8.2  nathanw #include <sys/malloc.h>
     75  1.28.8.2  nathanw #include <sys/uio.h>
     76  1.28.8.2  nathanw #include <sys/syslog.h>
     77  1.28.8.2  nathanw #include <sys/queue.h>
     78  1.28.8.2  nathanw #include <sys/proc.h>
     79  1.28.8.2  nathanw #include <sys/fdio.h>
     80  1.28.8.2  nathanw #include <sys/conf.h>
     81  1.28.8.2  nathanw #include <sys/device.h>
     82  1.28.8.2  nathanw 
     83  1.28.8.2  nathanw #include <uvm/uvm_extern.h>
     84  1.28.8.2  nathanw 
     85  1.28.8.2  nathanw #include <machine/cpu.h>
     86  1.28.8.2  nathanw #include <machine/bus.h>
     87  1.28.8.2  nathanw #include <machine/iomap.h>
     88  1.28.8.2  nathanw #include <machine/mfp.h>
     89  1.28.8.2  nathanw 
     90  1.28.8.2  nathanw #include <atari/dev/hdfdreg.h>
     91  1.28.8.2  nathanw #include <atari/atari/intr.h>
     92  1.28.8.2  nathanw #include <atari/atari/device.h>
     93  1.28.8.2  nathanw 
     94  1.28.8.2  nathanw #include "locators.h"
     95  1.28.8.2  nathanw 
     96  1.28.8.2  nathanw /*
     97  1.28.8.2  nathanw  * {b,c}devsw[] function prototypes
     98  1.28.8.2  nathanw  */
     99  1.28.8.2  nathanw dev_type_open(fdopen);
    100  1.28.8.2  nathanw dev_type_close(fdclose);
    101  1.28.8.2  nathanw dev_type_read(fdread);
    102  1.28.8.2  nathanw dev_type_write(fdwrite);
    103  1.28.8.2  nathanw dev_type_ioctl(fdioctl);
    104  1.28.8.4  nathanw dev_type_strategy(fdstrategy);
    105  1.28.8.2  nathanw 
    106  1.28.8.2  nathanw volatile u_char	*fdio_addr;
    107  1.28.8.2  nathanw 
    108  1.28.8.2  nathanw #define wrt_fdc_reg(reg, val)	{ fdio_addr[reg] = val; }
    109  1.28.8.2  nathanw #define rd_fdc_reg(reg)		( fdio_addr[reg] )
    110  1.28.8.2  nathanw 
    111  1.28.8.2  nathanw #define	fdc_ienable()		MFP2->mf_ierb |= IB_DCHG;
    112  1.28.8.2  nathanw 
    113  1.28.8.2  nathanw /*
    114  1.28.8.2  nathanw  * Interface to the pseudo-dma handler
    115  1.28.8.2  nathanw  */
    116  1.28.8.2  nathanw void	fddma_intr(void);
    117  1.28.8.2  nathanw caddr_t	fddmaaddr  = NULL;
    118  1.28.8.2  nathanw int	fddmalen   = 0;
    119  1.28.8.2  nathanw 
    120  1.28.8.2  nathanw extern void	mfp_hdfd_nf __P((void)), mfp_hdfd_fifo __P((void));
    121  1.28.8.2  nathanw 
    122  1.28.8.2  nathanw /*
    123  1.28.8.2  nathanw  * Argument to fdcintr.....
    124  1.28.8.2  nathanw  */
    125  1.28.8.2  nathanw static void	*intr_arg = NULL; /* XXX: arg. to intr_establish() */
    126  1.28.8.2  nathanw 
    127  1.28.8.2  nathanw 
    128  1.28.8.2  nathanw 
    129  1.28.8.2  nathanw #define FDUNIT(dev)	(minor(dev) / 8)
    130  1.28.8.2  nathanw #define FDTYPE(dev)	(minor(dev) % 8)
    131  1.28.8.2  nathanw 
    132  1.28.8.2  nathanw /* XXX misuse a flag to identify format operation */
    133  1.28.8.2  nathanw #define B_FORMAT B_XXX
    134  1.28.8.2  nathanw 
    135  1.28.8.2  nathanw enum fdc_state {
    136  1.28.8.2  nathanw 	DEVIDLE = 0,
    137  1.28.8.2  nathanw 	MOTORWAIT,
    138  1.28.8.2  nathanw 	DOSEEK,
    139  1.28.8.2  nathanw 	SEEKWAIT,
    140  1.28.8.2  nathanw 	SEEKTIMEDOUT,
    141  1.28.8.2  nathanw 	SEEKCOMPLETE,
    142  1.28.8.2  nathanw 	DOIO,
    143  1.28.8.2  nathanw 	IOCOMPLETE,
    144  1.28.8.2  nathanw 	IOTIMEDOUT,
    145  1.28.8.2  nathanw 	DORESET,
    146  1.28.8.2  nathanw 	RESETCOMPLETE,
    147  1.28.8.2  nathanw 	RESETTIMEDOUT,
    148  1.28.8.2  nathanw 	DORECAL,
    149  1.28.8.2  nathanw 	RECALWAIT,
    150  1.28.8.2  nathanw 	RECALTIMEDOUT,
    151  1.28.8.2  nathanw 	RECALCOMPLETE,
    152  1.28.8.2  nathanw };
    153  1.28.8.2  nathanw 
    154  1.28.8.2  nathanw /* software state, per controller */
    155  1.28.8.2  nathanw struct fdc_softc {
    156  1.28.8.2  nathanw 	struct device	sc_dev;		/* boilerplate */
    157  1.28.8.2  nathanw 
    158  1.28.8.2  nathanw 	struct callout sc_timo_ch;	/* timeout callout */
    159  1.28.8.2  nathanw 	struct callout sc_intr_ch;	/* pseudo-intr callout */
    160  1.28.8.2  nathanw 
    161  1.28.8.2  nathanw 	struct fd_softc	*sc_fd[4];	/* pointers to children */
    162  1.28.8.2  nathanw 	TAILQ_HEAD(drivehead, fd_softc) sc_drives;
    163  1.28.8.2  nathanw 	enum fdc_state	sc_state;
    164  1.28.8.2  nathanw 	int		sc_errors;	/* number of retries so far */
    165  1.28.8.2  nathanw 	int		sc_overruns;	/* number of overruns so far */
    166  1.28.8.2  nathanw 	u_char		sc_status[7];	/* copy of registers */
    167  1.28.8.2  nathanw };
    168  1.28.8.2  nathanw 
    169  1.28.8.2  nathanw /* controller driver configuration */
    170  1.28.8.2  nathanw int	fdcprobe __P((struct device *, struct cfdata *, void *));
    171  1.28.8.2  nathanw int	fdprint __P((void *, const char *));
    172  1.28.8.2  nathanw void	fdcattach __P((struct device *, struct device *, void *));
    173  1.28.8.2  nathanw 
    174  1.28.8.5  nathanw CFATTACH_DECL(fdc, sizeof(struct fdc_softc),
    175  1.28.8.5  nathanw     fdcprobe, fdcattach, NULL, NULL);
    176  1.28.8.2  nathanw 
    177  1.28.8.2  nathanw /*
    178  1.28.8.2  nathanw  * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
    179  1.28.8.2  nathanw  * we tell them apart.
    180  1.28.8.2  nathanw  */
    181  1.28.8.2  nathanw struct fd_type {
    182  1.28.8.2  nathanw 	int	sectrac;	/* sectors per track */
    183  1.28.8.2  nathanw 	int	heads;		/* number of heads */
    184  1.28.8.2  nathanw 	int	seccyl;		/* sectors per cylinder */
    185  1.28.8.2  nathanw 	int	secsize;	/* size code for sectors */
    186  1.28.8.2  nathanw 	int	datalen;	/* data len when secsize = 0 */
    187  1.28.8.2  nathanw 	int	steprate;	/* step rate and head unload time */
    188  1.28.8.2  nathanw 	int	gap1;		/* gap len between sectors */
    189  1.28.8.2  nathanw 	int	gap2;		/* formatting gap */
    190  1.28.8.2  nathanw 	int	tracks;		/* total num of tracks */
    191  1.28.8.2  nathanw 	int	size;		/* size of disk in sectors */
    192  1.28.8.2  nathanw 	int	step;		/* steps per cylinder */
    193  1.28.8.2  nathanw 	int	rate;		/* transfer speed code */
    194  1.28.8.2  nathanw 	u_char	fillbyte;	/* format fill byte */
    195  1.28.8.2  nathanw 	u_char	interleave;	/* interleave factor (formatting) */
    196  1.28.8.2  nathanw 	char	*name;
    197  1.28.8.2  nathanw };
    198  1.28.8.2  nathanw 
    199  1.28.8.2  nathanw /*
    200  1.28.8.2  nathanw  * The order of entries in the following table is important -- BEWARE!
    201  1.28.8.2  nathanw  * The order of the types is the same as for the TT/Falcon....
    202  1.28.8.2  nathanw  */
    203  1.28.8.2  nathanw struct fd_type fd_types[] = {
    204  1.28.8.2  nathanw         /* 360kB in 720kB drive */
    205  1.28.8.2  nathanw         {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_125KBPS,0xf6,1,"360KB"  },
    206  1.28.8.2  nathanw         /* 3.5" 720kB diskette */
    207  1.28.8.2  nathanw         {  9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_125KBPS,0xf6,1,"720KB"  },
    208  1.28.8.2  nathanw         /* 1.44MB diskette */
    209  1.28.8.2  nathanw         { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_250KBPS,0xf6,1,"1.44MB" },
    210  1.28.8.2  nathanw };
    211  1.28.8.2  nathanw 
    212  1.28.8.2  nathanw /* software state, per disk (with up to 4 disks per ctlr) */
    213  1.28.8.2  nathanw struct fd_softc {
    214  1.28.8.2  nathanw 	struct device	sc_dev;
    215  1.28.8.2  nathanw 	struct disk	sc_dk;
    216  1.28.8.2  nathanw 
    217  1.28.8.2  nathanw 	struct fd_type	*sc_deftype;	/* default type descriptor */
    218  1.28.8.2  nathanw 	struct fd_type	*sc_type;	/* current type descriptor */
    219  1.28.8.2  nathanw 
    220  1.28.8.2  nathanw 	struct callout	sc_motoron_ch;
    221  1.28.8.2  nathanw 	struct callout	sc_motoroff_ch;
    222  1.28.8.2  nathanw 
    223  1.28.8.2  nathanw 	daddr_t		sc_blkno;	/* starting block number */
    224  1.28.8.2  nathanw 	int		sc_bcount;	/* byte count left */
    225  1.28.8.2  nathanw  	int		sc_opts;	/* user-set options */
    226  1.28.8.2  nathanw 	int		sc_skip;	/* bytes already transferred */
    227  1.28.8.2  nathanw 	int		sc_nblks;	/* #blocks currently transferring */
    228  1.28.8.2  nathanw 	int		sc_nbytes;	/* #bytes currently transferring */
    229  1.28.8.2  nathanw 
    230  1.28.8.2  nathanw 	int		sc_drive;	/* physical unit number */
    231  1.28.8.2  nathanw 	int		sc_flags;
    232  1.28.8.2  nathanw #define	FD_OPEN		0x01		/* it's open */
    233  1.28.8.2  nathanw #define	FD_MOTOR	0x02		/* motor should be on */
    234  1.28.8.2  nathanw #define	FD_MOTOR_WAIT	0x04		/* motor coming up */
    235  1.28.8.2  nathanw #define	FD_HAVELAB	0x08		/* got a disklabel */
    236  1.28.8.2  nathanw 	int		sc_cylin;	/* where we think the head is */
    237  1.28.8.2  nathanw 
    238  1.28.8.2  nathanw 	void		*sc_sdhook;	/* saved shutdown hook for drive. */
    239  1.28.8.2  nathanw 
    240  1.28.8.2  nathanw 	TAILQ_ENTRY(fd_softc) sc_drivechain;
    241  1.28.8.2  nathanw 	int		sc_ops;		/* I/O ops since last switch */
    242  1.28.8.3  nathanw 	struct bufq_state sc_q;		/* pending I/O requests */
    243  1.28.8.2  nathanw 	int		sc_active;	/* number of active I/O operations */
    244  1.28.8.2  nathanw };
    245  1.28.8.2  nathanw 
    246  1.28.8.2  nathanw /* floppy driver configuration */
    247  1.28.8.2  nathanw int	fdprobe __P((struct device *, struct cfdata *, void *));
    248  1.28.8.2  nathanw void	fdattach __P((struct device *, struct device *, void *));
    249  1.28.8.2  nathanw 
    250  1.28.8.5  nathanw CFATTACH_DECL(hdfd, sizeof(struct fd_softc),
    251  1.28.8.5  nathanw     fdprobe, fdattach, NULL, NULL);
    252  1.28.8.2  nathanw 
    253  1.28.8.2  nathanw extern struct cfdriver hdfd_cd;
    254  1.28.8.2  nathanw 
    255  1.28.8.4  nathanw const struct bdevsw fd_bdevsw = {
    256  1.28.8.4  nathanw 	fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK
    257  1.28.8.4  nathanw };
    258  1.28.8.4  nathanw 
    259  1.28.8.4  nathanw const struct cdevsw fd_cdevsw = {
    260  1.28.8.4  nathanw 	fdopen, fdclose, fdread, fdwrite, fdioctl,
    261  1.28.8.6  nathanw 	nostop, notty, nopoll, nommap, nokqfilter, D_DISK
    262  1.28.8.4  nathanw };
    263  1.28.8.4  nathanw 
    264  1.28.8.2  nathanw void	fdstart __P((struct fd_softc *));
    265  1.28.8.2  nathanw 
    266  1.28.8.2  nathanw struct dkdriver fddkdriver = { fdstrategy };
    267  1.28.8.2  nathanw 
    268  1.28.8.2  nathanw void	fd_set_motor __P((struct fdc_softc *fdc, int reset));
    269  1.28.8.2  nathanw void	fd_motor_off __P((void *arg));
    270  1.28.8.2  nathanw void	fd_motor_on __P((void *arg));
    271  1.28.8.2  nathanw int	fdcresult __P((struct fdc_softc *fdc));
    272  1.28.8.2  nathanw int	out_fdc __P((u_char x));
    273  1.28.8.2  nathanw void	fdc_ctrl_intr __P((struct clockframe));
    274  1.28.8.2  nathanw void	fdcstart __P((struct fdc_softc *fdc));
    275  1.28.8.2  nathanw void	fdcstatus __P((struct device *dv, int n, char *s));
    276  1.28.8.2  nathanw void	fdctimeout __P((void *arg));
    277  1.28.8.2  nathanw void	fdcpseudointr __P((void *arg));
    278  1.28.8.2  nathanw int	fdcintr __P((void *));
    279  1.28.8.2  nathanw void	fdcretry __P((struct fdc_softc *fdc));
    280  1.28.8.2  nathanw void	fdfinish __P((struct fd_softc *fd, struct buf *bp));
    281  1.28.8.2  nathanw int	fdformat __P((dev_t, struct ne7_fd_formb *, struct proc *));
    282  1.28.8.2  nathanw 
    283  1.28.8.2  nathanw static void	fdgetdisklabel __P((struct fd_softc *, dev_t));
    284  1.28.8.2  nathanw static void	fdgetdefaultlabel __P((struct fd_softc *, struct disklabel *,
    285  1.28.8.2  nathanw 		    int));
    286  1.28.8.2  nathanw 
    287  1.28.8.2  nathanw __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
    288  1.28.8.2  nathanw 
    289  1.28.8.2  nathanw int
    290  1.28.8.2  nathanw fdcprobe(parent, cfp, aux)
    291  1.28.8.2  nathanw 	struct device	*parent;
    292  1.28.8.2  nathanw 	struct cfdata	*cfp;
    293  1.28.8.2  nathanw 	void		*aux;
    294  1.28.8.2  nathanw {
    295  1.28.8.2  nathanw 	static int	fdc_matched = 0;
    296  1.28.8.2  nathanw 	bus_space_tag_t mb_tag;
    297  1.28.8.2  nathanw 
    298  1.28.8.2  nathanw 	/* Match only once */
    299  1.28.8.2  nathanw 	if(strcmp("fdc", aux) || fdc_matched)
    300  1.28.8.2  nathanw 		return(0);
    301  1.28.8.2  nathanw 
    302  1.28.8.2  nathanw 	if (!atari_realconfig)
    303  1.28.8.2  nathanw 		return 0;
    304  1.28.8.2  nathanw 
    305  1.28.8.2  nathanw 	if ((mb_tag = mb_alloc_bus_space_tag()) == NULL)
    306  1.28.8.2  nathanw 		return 0;
    307  1.28.8.2  nathanw 
    308  1.28.8.2  nathanw 	if (bus_space_map(mb_tag, FD_IOBASE, FD_IOSIZE, 0,
    309  1.28.8.2  nathanw 						(caddr_t*)&fdio_addr)) {
    310  1.28.8.2  nathanw 		printf("fdcprobe: cannot map io-area\n");
    311  1.28.8.2  nathanw 		mb_free_bus_space_tag(mb_tag);
    312  1.28.8.2  nathanw 		return (0);
    313  1.28.8.2  nathanw 	}
    314  1.28.8.2  nathanw 
    315  1.28.8.2  nathanw #ifdef FD_DEBUG
    316  1.28.8.2  nathanw 	printf("fdcprobe: I/O mapping done va: %p\n", fdio_addr);
    317  1.28.8.2  nathanw #endif
    318  1.28.8.2  nathanw 
    319  1.28.8.2  nathanw 	/* reset */
    320  1.28.8.2  nathanw 	wrt_fdc_reg(fdout, 0);
    321  1.28.8.2  nathanw 	delay(100);
    322  1.28.8.2  nathanw 	wrt_fdc_reg(fdout, FDO_FRST);
    323  1.28.8.2  nathanw 
    324  1.28.8.2  nathanw 	/* see if it can handle a command */
    325  1.28.8.2  nathanw 	if (out_fdc(NE7CMD_SPECIFY) < 0)
    326  1.28.8.2  nathanw 		goto out;
    327  1.28.8.2  nathanw 	out_fdc(0xdf);
    328  1.28.8.2  nathanw 	out_fdc(7);
    329  1.28.8.2  nathanw 
    330  1.28.8.2  nathanw 	fdc_matched = 1;
    331  1.28.8.2  nathanw 
    332  1.28.8.2  nathanw  out:
    333  1.28.8.2  nathanw 	if (fdc_matched == 0) {
    334  1.28.8.2  nathanw 		bus_space_unmap(mb_tag, (caddr_t)fdio_addr, FD_IOSIZE);
    335  1.28.8.2  nathanw 		mb_free_bus_space_tag(mb_tag);
    336  1.28.8.2  nathanw 	}
    337  1.28.8.2  nathanw 
    338  1.28.8.2  nathanw 	return fdc_matched;
    339  1.28.8.2  nathanw }
    340  1.28.8.2  nathanw 
    341  1.28.8.2  nathanw /*
    342  1.28.8.2  nathanw  * Arguments passed between fdcattach and fdprobe.
    343  1.28.8.2  nathanw  */
    344  1.28.8.2  nathanw struct fdc_attach_args {
    345  1.28.8.2  nathanw 	int fa_drive;
    346  1.28.8.2  nathanw 	struct fd_type *fa_deftype;
    347  1.28.8.2  nathanw };
    348  1.28.8.2  nathanw 
    349  1.28.8.2  nathanw /*
    350  1.28.8.2  nathanw  * Print the location of a disk drive (called just before attaching the
    351  1.28.8.2  nathanw  * the drive).  If `fdc' is not NULL, the drive was found but was not
    352  1.28.8.2  nathanw  * in the system config file; print the drive name as well.
    353  1.28.8.2  nathanw  * Return QUIET (config_find ignores this if the device was configured) to
    354  1.28.8.2  nathanw  * avoid printing `fdN not configured' messages.
    355  1.28.8.2  nathanw  */
    356  1.28.8.2  nathanw int
    357  1.28.8.2  nathanw fdprint(aux, fdc)
    358  1.28.8.2  nathanw 	void *aux;
    359  1.28.8.2  nathanw 	const char *fdc;
    360  1.28.8.2  nathanw {
    361  1.28.8.2  nathanw 	register struct fdc_attach_args *fa = aux;
    362  1.28.8.2  nathanw 
    363  1.28.8.2  nathanw 	if (!fdc)
    364  1.28.8.7  thorpej 		aprint_normal(" drive %d", fa->fa_drive);
    365  1.28.8.2  nathanw 	return QUIET;
    366  1.28.8.2  nathanw }
    367  1.28.8.2  nathanw 
    368  1.28.8.2  nathanw void
    369  1.28.8.2  nathanw fdcattach(parent, self, aux)
    370  1.28.8.2  nathanw 	struct device *parent, *self;
    371  1.28.8.2  nathanw 	void *aux;
    372  1.28.8.2  nathanw {
    373  1.28.8.2  nathanw 	struct fdc_softc	*fdc = (void *)self;
    374  1.28.8.2  nathanw 	struct fdc_attach_args	fa;
    375  1.28.8.2  nathanw 	int			has_fifo;
    376  1.28.8.2  nathanw 
    377  1.28.8.2  nathanw 	has_fifo = 0;
    378  1.28.8.2  nathanw 
    379  1.28.8.2  nathanw 	fdc->sc_state = DEVIDLE;
    380  1.28.8.2  nathanw 	TAILQ_INIT(&fdc->sc_drives);
    381  1.28.8.2  nathanw 
    382  1.28.8.2  nathanw 	out_fdc(NE7CMD_CONFIGURE);
    383  1.28.8.2  nathanw 	if (out_fdc(0) == 0) {
    384  1.28.8.2  nathanw 		out_fdc(0x1a);	/* No polling, fifo depth = 10	*/
    385  1.28.8.2  nathanw 		out_fdc(0);
    386  1.28.8.2  nathanw 
    387  1.28.8.2  nathanw 		/* Retain configuration across resets	*/
    388  1.28.8.2  nathanw 		out_fdc(NE7CMD_LOCK);
    389  1.28.8.2  nathanw 		(void)fdcresult(fdc);
    390  1.28.8.2  nathanw 		has_fifo = 1;
    391  1.28.8.2  nathanw 	}
    392  1.28.8.2  nathanw 	else {
    393  1.28.8.2  nathanw 		(void)rd_fdc_reg(fddata);
    394  1.28.8.2  nathanw 		printf(": no fifo");
    395  1.28.8.2  nathanw 	}
    396  1.28.8.2  nathanw 
    397  1.28.8.2  nathanw 	printf("\n");
    398  1.28.8.2  nathanw 
    399  1.28.8.2  nathanw 	callout_init(&fdc->sc_timo_ch);
    400  1.28.8.2  nathanw 	callout_init(&fdc->sc_intr_ch);
    401  1.28.8.2  nathanw 
    402  1.28.8.2  nathanw 	if (intr_establish(22, USER_VEC|FAST_VEC, 0,
    403  1.28.8.2  nathanw 			   (hw_ifun_t)(has_fifo ? mfp_hdfd_fifo : mfp_hdfd_nf),
    404  1.28.8.2  nathanw 			   NULL) == NULL) {
    405  1.28.8.2  nathanw 		printf("fdcattach: Can't establish interrupt\n");
    406  1.28.8.2  nathanw 		return;
    407  1.28.8.2  nathanw 	}
    408  1.28.8.2  nathanw 
    409  1.28.8.2  nathanw 	/*
    410  1.28.8.2  nathanw 	 * Setup the interrupt logic.
    411  1.28.8.2  nathanw 	 */
    412  1.28.8.2  nathanw 	MFP2->mf_iprb  = (u_int8_t)~IB_DCHG;
    413  1.28.8.2  nathanw 	MFP2->mf_imrb |= IB_DCHG;
    414  1.28.8.2  nathanw 	MFP2->mf_aer  |= 0x10; /* fdc int low->high */
    415  1.28.8.2  nathanw 
    416  1.28.8.2  nathanw 	/* physical limit: four drives per controller. */
    417  1.28.8.2  nathanw 	for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
    418  1.28.8.2  nathanw 		/*
    419  1.28.8.2  nathanw 		 * XXX: Choose something sensible as a default...
    420  1.28.8.2  nathanw 		 */
    421  1.28.8.2  nathanw 		fa.fa_deftype = &fd_types[2]; /* 1.44MB */
    422  1.28.8.2  nathanw 		(void)config_found(self, (void *)&fa, fdprint);
    423  1.28.8.2  nathanw 	}
    424  1.28.8.2  nathanw }
    425  1.28.8.2  nathanw 
    426  1.28.8.2  nathanw int
    427  1.28.8.2  nathanw fdprobe(parent, cfp, aux)
    428  1.28.8.2  nathanw 	struct device	*parent;
    429  1.28.8.2  nathanw 	struct cfdata	*cfp;
    430  1.28.8.2  nathanw 	void		*aux;
    431  1.28.8.2  nathanw {
    432  1.28.8.2  nathanw 	struct fdc_softc	*fdc = (void *)parent;
    433  1.28.8.2  nathanw 	struct fdc_attach_args	*fa = aux;
    434  1.28.8.2  nathanw 	int			drive = fa->fa_drive;
    435  1.28.8.2  nathanw 	int			n;
    436  1.28.8.2  nathanw 
    437  1.28.8.2  nathanw 	if (cfp->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
    438  1.28.8.2  nathanw 	    cfp->cf_loc[FDCCF_UNIT] != drive)
    439  1.28.8.2  nathanw 		return 0;
    440  1.28.8.2  nathanw 	/*
    441  1.28.8.2  nathanw 	 * XXX
    442  1.28.8.2  nathanw 	 * This is to work around some odd interactions between this driver
    443  1.28.8.2  nathanw 	 * and SMC Ethernet cards.
    444  1.28.8.2  nathanw 	 */
    445  1.28.8.2  nathanw 	if (cfp->cf_loc[FDCCF_UNIT] == FDCCF_UNIT_DEFAULT && drive >= 2)
    446  1.28.8.2  nathanw 		return 0;
    447  1.28.8.2  nathanw 
    448  1.28.8.2  nathanw 	/* select drive and turn on motor */
    449  1.28.8.2  nathanw 	wrt_fdc_reg(fdout, drive | FDO_FRST | FDO_MOEN(drive));
    450  1.28.8.2  nathanw 
    451  1.28.8.2  nathanw 	/* wait for motor to spin up */
    452  1.28.8.2  nathanw 	delay(250000);
    453  1.28.8.2  nathanw 	out_fdc(NE7CMD_RECAL);
    454  1.28.8.2  nathanw 	out_fdc(drive);
    455  1.28.8.2  nathanw 
    456  1.28.8.2  nathanw 	/* wait for recalibrate */
    457  1.28.8.2  nathanw 	delay(2000000);
    458  1.28.8.2  nathanw 	out_fdc(NE7CMD_SENSEI);
    459  1.28.8.2  nathanw 	n = fdcresult(fdc);
    460  1.28.8.2  nathanw 
    461  1.28.8.2  nathanw #ifdef FD_DEBUG
    462  1.28.8.2  nathanw 	{
    463  1.28.8.2  nathanw 		int i;
    464  1.28.8.2  nathanw 		printf("fdprobe: status");
    465  1.28.8.2  nathanw 		for (i = 0; i < n; i++)
    466  1.28.8.2  nathanw 			printf(" %x", fdc->sc_status[i]);
    467  1.28.8.2  nathanw 		printf("\n");
    468  1.28.8.2  nathanw 	}
    469  1.28.8.2  nathanw #endif
    470  1.28.8.2  nathanw 	intr_arg = (void*)fdc;
    471  1.28.8.2  nathanw 	if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20)
    472  1.28.8.2  nathanw 		return 0;
    473  1.28.8.2  nathanw 	/* turn off motor */
    474  1.28.8.2  nathanw 	wrt_fdc_reg(fdout, FDO_FRST);
    475  1.28.8.2  nathanw 
    476  1.28.8.2  nathanw 	return 1;
    477  1.28.8.2  nathanw }
    478  1.28.8.2  nathanw 
    479  1.28.8.2  nathanw /*
    480  1.28.8.2  nathanw  * Controller is working, and drive responded.  Attach it.
    481  1.28.8.2  nathanw  */
    482  1.28.8.2  nathanw void
    483  1.28.8.2  nathanw fdattach(parent, self, aux)
    484  1.28.8.2  nathanw 	struct device *parent, *self;
    485  1.28.8.2  nathanw 	void *aux;
    486  1.28.8.2  nathanw {
    487  1.28.8.2  nathanw 	struct fdc_softc	*fdc  = (void *)parent;
    488  1.28.8.2  nathanw 	struct fd_softc		*fd   = (void *)self;
    489  1.28.8.2  nathanw 	struct fdc_attach_args	*fa   = aux;
    490  1.28.8.2  nathanw 	struct fd_type		*type = fa->fa_deftype;
    491  1.28.8.2  nathanw 	int			drive = fa->fa_drive;
    492  1.28.8.2  nathanw 
    493  1.28.8.2  nathanw 	callout_init(&fd->sc_motoron_ch);
    494  1.28.8.2  nathanw 	callout_init(&fd->sc_motoroff_ch);
    495  1.28.8.2  nathanw 
    496  1.28.8.2  nathanw 	/* XXX Allow `flags' to override device type? */
    497  1.28.8.2  nathanw 
    498  1.28.8.2  nathanw 	if (type)
    499  1.28.8.2  nathanw 		printf(": %s %d cyl, %d head, %d sec\n", type->name,
    500  1.28.8.2  nathanw 		    type->tracks, type->heads, type->sectrac);
    501  1.28.8.2  nathanw 	else
    502  1.28.8.2  nathanw 		printf(": density unknown\n");
    503  1.28.8.2  nathanw 
    504  1.28.8.3  nathanw 	bufq_alloc(&fd->sc_q, BUFQ_DISKSORT|BUFQ_SORT_CYLINDER);
    505  1.28.8.2  nathanw 	fd->sc_cylin      = -1;
    506  1.28.8.2  nathanw 	fd->sc_drive      = drive;
    507  1.28.8.2  nathanw 	fd->sc_deftype    = type;
    508  1.28.8.2  nathanw 	fdc->sc_fd[drive] = fd;
    509  1.28.8.2  nathanw 
    510  1.28.8.2  nathanw 	/*
    511  1.28.8.2  nathanw 	 * Initialize and attach the disk structure.
    512  1.28.8.2  nathanw 	 */
    513  1.28.8.2  nathanw 	fd->sc_dk.dk_name   = fd->sc_dev.dv_xname;
    514  1.28.8.2  nathanw 	fd->sc_dk.dk_driver = &fddkdriver;
    515  1.28.8.2  nathanw 	disk_attach(&fd->sc_dk);
    516  1.28.8.2  nathanw 
    517  1.28.8.2  nathanw 	/* Needed to power off if the motor is on when we halt. */
    518  1.28.8.2  nathanw 	fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd);
    519  1.28.8.2  nathanw }
    520  1.28.8.2  nathanw 
    521  1.28.8.2  nathanw /*
    522  1.28.8.2  nathanw  * This is called from the assembly part of the interrupt handler
    523  1.28.8.2  nathanw  * when it is clear that the interrupt was not related to shoving
    524  1.28.8.2  nathanw  * data.
    525  1.28.8.2  nathanw  */
    526  1.28.8.2  nathanw void
    527  1.28.8.2  nathanw fdc_ctrl_intr(frame)
    528  1.28.8.2  nathanw 	struct clockframe frame;
    529  1.28.8.2  nathanw {
    530  1.28.8.2  nathanw 	int	s;
    531  1.28.8.2  nathanw 
    532  1.28.8.2  nathanw 	/*
    533  1.28.8.2  nathanw 	 * Disable further interrupts. The fdcintr() routine
    534  1.28.8.2  nathanw 	 * explicitly enables them when needed.
    535  1.28.8.2  nathanw 	 */
    536  1.28.8.2  nathanw 	MFP2->mf_ierb &= ~IB_DCHG;
    537  1.28.8.2  nathanw 
    538  1.28.8.2  nathanw 	/*
    539  1.28.8.2  nathanw 	 * Set fddmalen to zero so no pseudo-dma transfers will
    540  1.28.8.2  nathanw 	 * occur.
    541  1.28.8.2  nathanw 	 */
    542  1.28.8.2  nathanw 	fddmalen = 0;
    543  1.28.8.2  nathanw 
    544  1.28.8.2  nathanw 	if (!BASEPRI(frame.cf_sr)) {
    545  1.28.8.2  nathanw 		/*
    546  1.28.8.2  nathanw 		 * We don't want to stay on ipl6.....
    547  1.28.8.2  nathanw 		 */
    548  1.28.8.2  nathanw 		add_sicallback((si_farg)fdcpseudointr, intr_arg, 0);
    549  1.28.8.2  nathanw 	}
    550  1.28.8.2  nathanw 	else {
    551  1.28.8.2  nathanw 		s = splbio();
    552  1.28.8.2  nathanw 		(void) fdcintr(intr_arg);
    553  1.28.8.2  nathanw 		splx(s);
    554  1.28.8.2  nathanw 	}
    555  1.28.8.2  nathanw }
    556  1.28.8.2  nathanw 
    557  1.28.8.2  nathanw __inline struct fd_type *
    558  1.28.8.2  nathanw fd_dev_to_type(fd, dev)
    559  1.28.8.2  nathanw 	struct fd_softc *fd;
    560  1.28.8.2  nathanw 	dev_t dev;
    561  1.28.8.2  nathanw {
    562  1.28.8.2  nathanw 	int type = FDTYPE(dev);
    563  1.28.8.2  nathanw 
    564  1.28.8.2  nathanw 	if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
    565  1.28.8.2  nathanw 		return NULL;
    566  1.28.8.2  nathanw 	return type ? &fd_types[type - 1] : fd->sc_deftype;
    567  1.28.8.2  nathanw }
    568  1.28.8.2  nathanw 
    569  1.28.8.2  nathanw void
    570  1.28.8.2  nathanw fdstrategy(bp)
    571  1.28.8.2  nathanw 	register struct buf *bp;	/* IO operation to perform */
    572  1.28.8.2  nathanw {
    573  1.28.8.2  nathanw 	struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(bp->b_dev)];
    574  1.28.8.2  nathanw 	int sz;
    575  1.28.8.2  nathanw  	int s;
    576  1.28.8.2  nathanw 
    577  1.28.8.2  nathanw 	/* Valid unit, controller, and request? */
    578  1.28.8.2  nathanw 	if (bp->b_blkno < 0 ||
    579  1.28.8.2  nathanw 	    ((bp->b_bcount % FDC_BSIZE) != 0 &&
    580  1.28.8.2  nathanw 	     (bp->b_flags & B_FORMAT) == 0)) {
    581  1.28.8.2  nathanw 		bp->b_error = EINVAL;
    582  1.28.8.2  nathanw 		goto bad;
    583  1.28.8.2  nathanw 	}
    584  1.28.8.2  nathanw 
    585  1.28.8.2  nathanw 	/* If it's a null transfer, return immediately. */
    586  1.28.8.2  nathanw 	if (bp->b_bcount == 0)
    587  1.28.8.2  nathanw 		goto done;
    588  1.28.8.2  nathanw 
    589  1.28.8.2  nathanw 	sz = howmany(bp->b_bcount, FDC_BSIZE);
    590  1.28.8.2  nathanw 
    591  1.28.8.2  nathanw 	if (bp->b_blkno + sz > fd->sc_type->size) {
    592  1.28.8.2  nathanw 		sz = fd->sc_type->size - bp->b_blkno;
    593  1.28.8.2  nathanw 		if (sz == 0) {
    594  1.28.8.2  nathanw 			/* If exactly at end of disk, return EOF. */
    595  1.28.8.2  nathanw 			goto done;
    596  1.28.8.2  nathanw 		}
    597  1.28.8.2  nathanw 		if (sz < 0) {
    598  1.28.8.2  nathanw 			/* If past end of disk, return EINVAL. */
    599  1.28.8.2  nathanw 			bp->b_error = EINVAL;
    600  1.28.8.2  nathanw 			goto bad;
    601  1.28.8.2  nathanw 		}
    602  1.28.8.2  nathanw 		/* Otherwise, truncate request. */
    603  1.28.8.2  nathanw 		bp->b_bcount = sz << DEV_BSHIFT;
    604  1.28.8.2  nathanw 	}
    605  1.28.8.2  nathanw 
    606  1.28.8.2  nathanw 	bp->b_rawblkno = bp->b_blkno;
    607  1.28.8.2  nathanw  	bp->b_cylinder = bp->b_blkno / (FDC_BSIZE/DEV_BSIZE) / fd->sc_type->seccyl;
    608  1.28.8.2  nathanw 
    609  1.28.8.2  nathanw #ifdef FD_DEBUG
    610  1.28.8.2  nathanw 	printf("fdstrategy: b_blkno %d b_bcount %ld blkno %ld cylin %ld sz"
    611  1.28.8.2  nathanw 		" %d\n", bp->b_blkno, bp->b_bcount, (long)fd->sc_blkno,
    612  1.28.8.2  nathanw 		bp->b_cylinder, sz);
    613  1.28.8.2  nathanw #endif
    614  1.28.8.2  nathanw 
    615  1.28.8.2  nathanw 	/* Queue transfer on drive, activate drive and controller if idle. */
    616  1.28.8.2  nathanw 	s = splbio();
    617  1.28.8.3  nathanw 	BUFQ_PUT(&fd->sc_q, bp);
    618  1.28.8.2  nathanw 	callout_stop(&fd->sc_motoroff_ch);		/* a good idea */
    619  1.28.8.2  nathanw 	if (fd->sc_active == 0)
    620  1.28.8.2  nathanw 		fdstart(fd);
    621  1.28.8.2  nathanw #ifdef DIAGNOSTIC
    622  1.28.8.2  nathanw 	else {
    623  1.28.8.2  nathanw 		struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    624  1.28.8.2  nathanw 		if (fdc->sc_state == DEVIDLE) {
    625  1.28.8.2  nathanw 			printf("fdstrategy: controller inactive\n");
    626  1.28.8.2  nathanw 			fdcstart(fdc);
    627  1.28.8.2  nathanw 		}
    628  1.28.8.2  nathanw 	}
    629  1.28.8.2  nathanw #endif
    630  1.28.8.2  nathanw 	splx(s);
    631  1.28.8.2  nathanw 	return;
    632  1.28.8.2  nathanw 
    633  1.28.8.2  nathanw bad:
    634  1.28.8.2  nathanw 	bp->b_flags |= B_ERROR;
    635  1.28.8.2  nathanw done:
    636  1.28.8.2  nathanw 	/* Toss transfer; we're done early. */
    637  1.28.8.2  nathanw 	bp->b_resid = bp->b_bcount;
    638  1.28.8.2  nathanw 	biodone(bp);
    639  1.28.8.2  nathanw }
    640  1.28.8.2  nathanw 
    641  1.28.8.2  nathanw void
    642  1.28.8.2  nathanw fdstart(fd)
    643  1.28.8.2  nathanw 	struct fd_softc *fd;
    644  1.28.8.2  nathanw {
    645  1.28.8.2  nathanw 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    646  1.28.8.2  nathanw 	int active = fdc->sc_drives.tqh_first != 0;
    647  1.28.8.2  nathanw 
    648  1.28.8.2  nathanw 	/* Link into controller queue. */
    649  1.28.8.2  nathanw 	fd->sc_active = 1;
    650  1.28.8.2  nathanw 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    651  1.28.8.2  nathanw 
    652  1.28.8.2  nathanw 	/* If controller not already active, start it. */
    653  1.28.8.2  nathanw 	if (!active)
    654  1.28.8.2  nathanw 		fdcstart(fdc);
    655  1.28.8.2  nathanw }
    656  1.28.8.2  nathanw 
    657  1.28.8.2  nathanw void
    658  1.28.8.2  nathanw fdfinish(fd, bp)
    659  1.28.8.2  nathanw 	struct fd_softc *fd;
    660  1.28.8.2  nathanw 	struct buf *bp;
    661  1.28.8.2  nathanw {
    662  1.28.8.2  nathanw 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    663  1.28.8.2  nathanw 
    664  1.28.8.2  nathanw 	/*
    665  1.28.8.2  nathanw 	 * Move this drive to the end of the queue to give others a `fair'
    666  1.28.8.2  nathanw 	 * chance.  We only force a switch if N operations are completed while
    667  1.28.8.2  nathanw 	 * another drive is waiting to be serviced, since there is a long motor
    668  1.28.8.2  nathanw 	 * startup delay whenever we switch.
    669  1.28.8.2  nathanw 	 */
    670  1.28.8.3  nathanw 	(void)BUFQ_GET(&fd->sc_q);
    671  1.28.8.2  nathanw 	if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
    672  1.28.8.2  nathanw 		fd->sc_ops = 0;
    673  1.28.8.2  nathanw 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
    674  1.28.8.3  nathanw 		if (BUFQ_PEEK(&fd->sc_q) != NULL)
    675  1.28.8.2  nathanw 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    676  1.28.8.2  nathanw 		else
    677  1.28.8.2  nathanw 			fd->sc_active = 0;
    678  1.28.8.2  nathanw 	}
    679  1.28.8.2  nathanw 	bp->b_resid = fd->sc_bcount;
    680  1.28.8.2  nathanw 	fd->sc_skip = 0;
    681  1.28.8.2  nathanw 
    682  1.28.8.2  nathanw 	biodone(bp);
    683  1.28.8.2  nathanw 	/* turn off motor 5s from now */
    684  1.28.8.2  nathanw 	callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
    685  1.28.8.2  nathanw 	fdc->sc_state = DEVIDLE;
    686  1.28.8.2  nathanw }
    687  1.28.8.2  nathanw 
    688  1.28.8.2  nathanw int
    689  1.28.8.2  nathanw fdread(dev, uio, flags)
    690  1.28.8.2  nathanw 	dev_t dev;
    691  1.28.8.2  nathanw 	struct uio *uio;
    692  1.28.8.2  nathanw 	int flags;
    693  1.28.8.2  nathanw {
    694  1.28.8.2  nathanw 	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
    695  1.28.8.2  nathanw }
    696  1.28.8.2  nathanw 
    697  1.28.8.2  nathanw int
    698  1.28.8.2  nathanw fdwrite(dev, uio, flags)
    699  1.28.8.2  nathanw 	dev_t dev;
    700  1.28.8.2  nathanw 	struct uio *uio;
    701  1.28.8.2  nathanw 	int flags;
    702  1.28.8.2  nathanw {
    703  1.28.8.2  nathanw 	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
    704  1.28.8.2  nathanw }
    705  1.28.8.2  nathanw 
    706  1.28.8.2  nathanw void
    707  1.28.8.2  nathanw fd_set_motor(fdc, reset)
    708  1.28.8.2  nathanw 	struct fdc_softc *fdc;
    709  1.28.8.2  nathanw 	int reset;
    710  1.28.8.2  nathanw {
    711  1.28.8.2  nathanw 	struct fd_softc *fd;
    712  1.28.8.2  nathanw 	u_char status;
    713  1.28.8.2  nathanw 	int n;
    714  1.28.8.2  nathanw 
    715  1.28.8.2  nathanw 	if ((fd = fdc->sc_drives.tqh_first) != NULL)
    716  1.28.8.2  nathanw 		status = fd->sc_drive;
    717  1.28.8.2  nathanw 	else
    718  1.28.8.2  nathanw 		status = 0;
    719  1.28.8.2  nathanw 	if (!reset)
    720  1.28.8.2  nathanw 		status |= FDO_FRST | FDO_FDMAEN;
    721  1.28.8.2  nathanw 	for (n = 0; n < 4; n++)
    722  1.28.8.2  nathanw 		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
    723  1.28.8.2  nathanw 			status |= FDO_MOEN(n);
    724  1.28.8.2  nathanw 	wrt_fdc_reg(fdout, status);
    725  1.28.8.2  nathanw }
    726  1.28.8.2  nathanw 
    727  1.28.8.2  nathanw void
    728  1.28.8.2  nathanw fd_motor_off(arg)
    729  1.28.8.2  nathanw 	void *arg;
    730  1.28.8.2  nathanw {
    731  1.28.8.2  nathanw 	struct fd_softc *fd = arg;
    732  1.28.8.2  nathanw 	int s;
    733  1.28.8.2  nathanw 
    734  1.28.8.2  nathanw 	s = splbio();
    735  1.28.8.2  nathanw 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
    736  1.28.8.2  nathanw 	fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0);
    737  1.28.8.2  nathanw 	splx(s);
    738  1.28.8.2  nathanw }
    739  1.28.8.2  nathanw 
    740  1.28.8.2  nathanw void
    741  1.28.8.2  nathanw fd_motor_on(arg)
    742  1.28.8.2  nathanw 	void *arg;
    743  1.28.8.2  nathanw {
    744  1.28.8.2  nathanw 	struct fd_softc *fd = arg;
    745  1.28.8.2  nathanw 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    746  1.28.8.2  nathanw 	int s;
    747  1.28.8.2  nathanw 
    748  1.28.8.2  nathanw 	s = splbio();
    749  1.28.8.2  nathanw 	fd->sc_flags &= ~FD_MOTOR_WAIT;
    750  1.28.8.2  nathanw 	if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
    751  1.28.8.2  nathanw 		(void) fdcintr(fdc);
    752  1.28.8.2  nathanw 	splx(s);
    753  1.28.8.2  nathanw }
    754  1.28.8.2  nathanw 
    755  1.28.8.2  nathanw int
    756  1.28.8.2  nathanw fdcresult(fdc)
    757  1.28.8.2  nathanw 	struct fdc_softc *fdc;
    758  1.28.8.2  nathanw {
    759  1.28.8.2  nathanw 	u_char i;
    760  1.28.8.2  nathanw 	int j = 100000,
    761  1.28.8.2  nathanw 	    n = 0;
    762  1.28.8.2  nathanw 
    763  1.28.8.2  nathanw 	for (; j; j--) {
    764  1.28.8.2  nathanw 		i = rd_fdc_reg(fdsts) & (NE7_DIO | NE7_RQM | NE7_CB);
    765  1.28.8.2  nathanw 		if (i == NE7_RQM)
    766  1.28.8.2  nathanw 			return n;
    767  1.28.8.2  nathanw 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
    768  1.28.8.2  nathanw 			if (n >= sizeof(fdc->sc_status)) {
    769  1.28.8.2  nathanw 				log(LOG_ERR, "fdcresult: overrun\n");
    770  1.28.8.2  nathanw 				return -1;
    771  1.28.8.2  nathanw 			}
    772  1.28.8.2  nathanw 			fdc->sc_status[n++] = rd_fdc_reg(fddata);
    773  1.28.8.2  nathanw 		}
    774  1.28.8.2  nathanw 		else delay(10);
    775  1.28.8.2  nathanw 	}
    776  1.28.8.2  nathanw 	log(LOG_ERR, "fdcresult: timeout\n");
    777  1.28.8.2  nathanw 	return -1;
    778  1.28.8.2  nathanw }
    779  1.28.8.2  nathanw 
    780  1.28.8.2  nathanw int
    781  1.28.8.2  nathanw out_fdc(x)
    782  1.28.8.2  nathanw 	u_char x;
    783  1.28.8.2  nathanw {
    784  1.28.8.2  nathanw 	int i = 100000;
    785  1.28.8.2  nathanw 
    786  1.28.8.2  nathanw 	while (((rd_fdc_reg(fdsts) & (NE7_DIO|NE7_RQM)) != NE7_RQM) && i-- > 0)
    787  1.28.8.2  nathanw 		delay(1);
    788  1.28.8.2  nathanw 	if (i <= 0)
    789  1.28.8.2  nathanw 		return -1;
    790  1.28.8.2  nathanw 	wrt_fdc_reg(fddata, x);
    791  1.28.8.2  nathanw 	return 0;
    792  1.28.8.2  nathanw }
    793  1.28.8.2  nathanw 
    794  1.28.8.2  nathanw int
    795  1.28.8.2  nathanw fdopen(dev, flags, mode, p)
    796  1.28.8.2  nathanw 	dev_t dev;
    797  1.28.8.2  nathanw 	int flags;
    798  1.28.8.2  nathanw 	int mode;
    799  1.28.8.2  nathanw 	struct proc *p;
    800  1.28.8.2  nathanw {
    801  1.28.8.2  nathanw  	int unit;
    802  1.28.8.2  nathanw 	struct fd_softc *fd;
    803  1.28.8.2  nathanw 	struct fd_type *type;
    804  1.28.8.2  nathanw 
    805  1.28.8.2  nathanw 	unit = FDUNIT(dev);
    806  1.28.8.2  nathanw 	if (unit >= hdfd_cd.cd_ndevs)
    807  1.28.8.2  nathanw 		return ENXIO;
    808  1.28.8.2  nathanw 	fd = hdfd_cd.cd_devs[unit];
    809  1.28.8.2  nathanw 	if (fd == 0)
    810  1.28.8.2  nathanw 		return ENXIO;
    811  1.28.8.2  nathanw 	type = fd_dev_to_type(fd, dev);
    812  1.28.8.2  nathanw 	if (type == NULL)
    813  1.28.8.2  nathanw 		return ENXIO;
    814  1.28.8.2  nathanw 
    815  1.28.8.2  nathanw 	if ((fd->sc_flags & FD_OPEN) != 0 &&
    816  1.28.8.2  nathanw 	    fd->sc_type != type)
    817  1.28.8.2  nathanw 		return EBUSY;
    818  1.28.8.2  nathanw 
    819  1.28.8.2  nathanw 	fd->sc_type = type;
    820  1.28.8.2  nathanw 	fd->sc_cylin = -1;
    821  1.28.8.2  nathanw 	fd->sc_flags |= FD_OPEN;
    822  1.28.8.2  nathanw 	fdgetdisklabel(fd, dev);
    823  1.28.8.2  nathanw 
    824  1.28.8.2  nathanw 	return 0;
    825  1.28.8.2  nathanw }
    826  1.28.8.2  nathanw 
    827  1.28.8.2  nathanw int
    828  1.28.8.2  nathanw fdclose(dev, flags, mode, p)
    829  1.28.8.2  nathanw 	dev_t dev;
    830  1.28.8.2  nathanw 	int flags;
    831  1.28.8.2  nathanw 	int mode;
    832  1.28.8.2  nathanw 	struct proc *p;
    833  1.28.8.2  nathanw {
    834  1.28.8.2  nathanw 	struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(dev)];
    835  1.28.8.2  nathanw 
    836  1.28.8.2  nathanw 	fd->sc_flags &= ~(FD_OPEN|FD_HAVELAB);
    837  1.28.8.2  nathanw 	fd->sc_opts  &= ~(FDOPT_NORETRY|FDOPT_SILENT);
    838  1.28.8.2  nathanw 	return 0;
    839  1.28.8.2  nathanw }
    840  1.28.8.2  nathanw 
    841  1.28.8.2  nathanw void
    842  1.28.8.2  nathanw fdcstart(fdc)
    843  1.28.8.2  nathanw 	struct fdc_softc *fdc;
    844  1.28.8.2  nathanw {
    845  1.28.8.2  nathanw 
    846  1.28.8.2  nathanw #ifdef DIAGNOSTIC
    847  1.28.8.2  nathanw 	/* only got here if controller's drive queue was inactive; should
    848  1.28.8.2  nathanw 	   be in idle state */
    849  1.28.8.2  nathanw 	if (fdc->sc_state != DEVIDLE) {
    850  1.28.8.2  nathanw 		printf("fdcstart: not idle\n");
    851  1.28.8.2  nathanw 		return;
    852  1.28.8.2  nathanw 	}
    853  1.28.8.2  nathanw #endif
    854  1.28.8.2  nathanw 	(void) fdcintr(fdc);
    855  1.28.8.2  nathanw }
    856  1.28.8.2  nathanw 
    857  1.28.8.2  nathanw void
    858  1.28.8.2  nathanw fdcstatus(dv, n, s)
    859  1.28.8.2  nathanw 	struct device *dv;
    860  1.28.8.2  nathanw 	int n;
    861  1.28.8.2  nathanw 	char *s;
    862  1.28.8.2  nathanw {
    863  1.28.8.2  nathanw 	struct fdc_softc *fdc = (void *)dv->dv_parent;
    864  1.28.8.2  nathanw 	char bits[64];
    865  1.28.8.2  nathanw 
    866  1.28.8.2  nathanw 	if (n == 0) {
    867  1.28.8.2  nathanw 		out_fdc(NE7CMD_SENSEI);
    868  1.28.8.2  nathanw 		(void) fdcresult(fdc);
    869  1.28.8.2  nathanw 		n = 2;
    870  1.28.8.2  nathanw 	}
    871  1.28.8.2  nathanw 
    872  1.28.8.2  nathanw 	printf("%s: %s", dv->dv_xname, s);
    873  1.28.8.2  nathanw 
    874  1.28.8.2  nathanw 	switch (n) {
    875  1.28.8.2  nathanw 	case 0:
    876  1.28.8.2  nathanw 		printf("\n");
    877  1.28.8.2  nathanw 		break;
    878  1.28.8.2  nathanw 	case 2:
    879  1.28.8.2  nathanw 		printf(" (st0 %s cyl %d)\n",
    880  1.28.8.2  nathanw 		    bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
    881  1.28.8.2  nathanw 		    bits, sizeof(bits)), fdc->sc_status[1]);
    882  1.28.8.2  nathanw 		break;
    883  1.28.8.2  nathanw 	case 7:
    884  1.28.8.2  nathanw 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
    885  1.28.8.2  nathanw 		    NE7_ST0BITS, bits, sizeof(bits)));
    886  1.28.8.2  nathanw 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
    887  1.28.8.2  nathanw 		    NE7_ST1BITS, bits, sizeof(bits)));
    888  1.28.8.2  nathanw 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
    889  1.28.8.2  nathanw 		    NE7_ST2BITS, bits, sizeof(bits)));
    890  1.28.8.2  nathanw 		printf(" cyl %d head %d sec %d)\n",
    891  1.28.8.2  nathanw 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
    892  1.28.8.2  nathanw 		break;
    893  1.28.8.2  nathanw #ifdef DIAGNOSTIC
    894  1.28.8.2  nathanw 	default:
    895  1.28.8.2  nathanw 		printf("\nfdcstatus: weird size");
    896  1.28.8.2  nathanw 		break;
    897  1.28.8.2  nathanw #endif
    898  1.28.8.2  nathanw 	}
    899  1.28.8.2  nathanw }
    900  1.28.8.2  nathanw 
    901  1.28.8.2  nathanw void
    902  1.28.8.2  nathanw fdctimeout(arg)
    903  1.28.8.2  nathanw 	void *arg;
    904  1.28.8.2  nathanw {
    905  1.28.8.2  nathanw 	struct fdc_softc *fdc = arg;
    906  1.28.8.2  nathanw 	struct fd_softc *fd = fdc->sc_drives.tqh_first;
    907  1.28.8.2  nathanw 	int s;
    908  1.28.8.2  nathanw 
    909  1.28.8.2  nathanw 	s = splbio();
    910  1.28.8.2  nathanw 	fdcstatus(&fd->sc_dev, 0, "timeout");
    911  1.28.8.2  nathanw 
    912  1.28.8.3  nathanw 	if (BUFQ_PEEK(&fd->sc_q) != NULL)
    913  1.28.8.2  nathanw 		fdc->sc_state++;
    914  1.28.8.2  nathanw 	else
    915  1.28.8.2  nathanw 		fdc->sc_state = DEVIDLE;
    916  1.28.8.2  nathanw 
    917  1.28.8.2  nathanw 	(void) fdcintr(fdc);
    918  1.28.8.2  nathanw 	splx(s);
    919  1.28.8.2  nathanw }
    920  1.28.8.2  nathanw 
    921  1.28.8.2  nathanw void
    922  1.28.8.2  nathanw fdcpseudointr(arg)
    923  1.28.8.2  nathanw 	void *arg;
    924  1.28.8.2  nathanw {
    925  1.28.8.2  nathanw 	int s;
    926  1.28.8.2  nathanw 
    927  1.28.8.2  nathanw 	/* Just ensure it has the right spl. */
    928  1.28.8.2  nathanw 	s = splbio();
    929  1.28.8.2  nathanw 	(void) fdcintr(arg);
    930  1.28.8.2  nathanw 	splx(s);
    931  1.28.8.2  nathanw }
    932  1.28.8.2  nathanw 
    933  1.28.8.2  nathanw int
    934  1.28.8.2  nathanw fdcintr(arg)
    935  1.28.8.2  nathanw 	void *arg;
    936  1.28.8.2  nathanw {
    937  1.28.8.2  nathanw 	struct fdc_softc	*fdc = arg;
    938  1.28.8.2  nathanw #define	st0	fdc->sc_status[0]
    939  1.28.8.2  nathanw #define	st1	fdc->sc_status[1]
    940  1.28.8.2  nathanw #define	cyl	fdc->sc_status[1]
    941  1.28.8.2  nathanw 
    942  1.28.8.2  nathanw 	struct fd_softc		*fd;
    943  1.28.8.2  nathanw 	struct buf		*bp;
    944  1.28.8.2  nathanw 	int			read, head, sec, i, nblks;
    945  1.28.8.2  nathanw 	struct fd_type		*type;
    946  1.28.8.2  nathanw 	struct ne7_fd_formb	*finfo = NULL;
    947  1.28.8.2  nathanw 
    948  1.28.8.2  nathanw loop:
    949  1.28.8.2  nathanw 	/* Is there a drive for the controller to do a transfer with? */
    950  1.28.8.2  nathanw 	fd = fdc->sc_drives.tqh_first;
    951  1.28.8.2  nathanw 	if (fd == NULL) {
    952  1.28.8.2  nathanw 		fdc->sc_state = DEVIDLE;
    953  1.28.8.2  nathanw  		return 1;
    954  1.28.8.2  nathanw 	}
    955  1.28.8.2  nathanw 
    956  1.28.8.2  nathanw 	/* Is there a transfer to this drive?  If not, deactivate drive. */
    957  1.28.8.3  nathanw 	bp = BUFQ_PEEK(&fd->sc_q);
    958  1.28.8.2  nathanw 	if (bp == NULL) {
    959  1.28.8.2  nathanw 		fd->sc_ops = 0;
    960  1.28.8.2  nathanw 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
    961  1.28.8.2  nathanw 		fd->sc_active = 0;
    962  1.28.8.2  nathanw 		goto loop;
    963  1.28.8.2  nathanw 	}
    964  1.28.8.2  nathanw 
    965  1.28.8.2  nathanw 	if (bp->b_flags & B_FORMAT)
    966  1.28.8.2  nathanw 		finfo = (struct ne7_fd_formb *)bp->b_data;
    967  1.28.8.2  nathanw 
    968  1.28.8.2  nathanw 	switch (fdc->sc_state) {
    969  1.28.8.2  nathanw 	case DEVIDLE:
    970  1.28.8.2  nathanw 		fdc->sc_errors = 0;
    971  1.28.8.2  nathanw 		fdc->sc_overruns = 0;
    972  1.28.8.2  nathanw 		fd->sc_skip = 0;
    973  1.28.8.2  nathanw 		fd->sc_bcount = bp->b_bcount;
    974  1.28.8.2  nathanw 		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
    975  1.28.8.2  nathanw 		callout_stop(&fd->sc_motoroff_ch);
    976  1.28.8.2  nathanw 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
    977  1.28.8.2  nathanw 			fdc->sc_state = MOTORWAIT;
    978  1.28.8.2  nathanw 			return 1;
    979  1.28.8.2  nathanw 		}
    980  1.28.8.2  nathanw 		if ((fd->sc_flags & FD_MOTOR) == 0) {
    981  1.28.8.2  nathanw 			/* Turn on the motor, being careful about pairing. */
    982  1.28.8.2  nathanw 			struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
    983  1.28.8.2  nathanw 			if (ofd && ofd->sc_flags & FD_MOTOR) {
    984  1.28.8.2  nathanw 				callout_stop(&ofd->sc_motoroff_ch);
    985  1.28.8.2  nathanw 				ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
    986  1.28.8.2  nathanw 			}
    987  1.28.8.2  nathanw 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
    988  1.28.8.2  nathanw 			fd_set_motor(fdc, 0);
    989  1.28.8.2  nathanw 			fdc->sc_state = MOTORWAIT;
    990  1.28.8.2  nathanw 			/* Allow .25s for motor to stabilize. */
    991  1.28.8.2  nathanw 			callout_reset(&fd->sc_motoron_ch, hz / 4,
    992  1.28.8.2  nathanw 			    fd_motor_on, fd);
    993  1.28.8.2  nathanw 			return 1;
    994  1.28.8.2  nathanw 		}
    995  1.28.8.2  nathanw 		/* Make sure the right drive is selected. */
    996  1.28.8.2  nathanw 		fd_set_motor(fdc, 0);
    997  1.28.8.2  nathanw 
    998  1.28.8.2  nathanw 		/* fall through */
    999  1.28.8.2  nathanw 	case DOSEEK:
   1000  1.28.8.2  nathanw 	doseek:
   1001  1.28.8.2  nathanw 		if (fd->sc_cylin == bp->b_cylinder)
   1002  1.28.8.2  nathanw 			goto doio;
   1003  1.28.8.2  nathanw 
   1004  1.28.8.2  nathanw 		out_fdc(NE7CMD_SPECIFY);/* specify command */
   1005  1.28.8.2  nathanw 		out_fdc(fd->sc_type->steprate);
   1006  1.28.8.2  nathanw 		out_fdc(0x7);	/* XXX head load time == 6ms - non-dma */
   1007  1.28.8.2  nathanw 
   1008  1.28.8.2  nathanw 		fdc_ienable();
   1009  1.28.8.2  nathanw 
   1010  1.28.8.2  nathanw 		out_fdc(NE7CMD_SEEK);	/* seek function */
   1011  1.28.8.2  nathanw 		out_fdc(fd->sc_drive);	/* drive number */
   1012  1.28.8.2  nathanw 		out_fdc(bp->b_cylinder * fd->sc_type->step);
   1013  1.28.8.2  nathanw 
   1014  1.28.8.2  nathanw 		fd->sc_cylin = -1;
   1015  1.28.8.2  nathanw 		fdc->sc_state = SEEKWAIT;
   1016  1.28.8.2  nathanw 
   1017  1.28.8.2  nathanw 		fd->sc_dk.dk_seek++;
   1018  1.28.8.2  nathanw 		disk_busy(&fd->sc_dk);
   1019  1.28.8.2  nathanw 
   1020  1.28.8.2  nathanw 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
   1021  1.28.8.2  nathanw 		return 1;
   1022  1.28.8.2  nathanw 
   1023  1.28.8.2  nathanw 	case DOIO:
   1024  1.28.8.2  nathanw 	doio:
   1025  1.28.8.2  nathanw 		if (finfo)
   1026  1.28.8.2  nathanw 			fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
   1027  1.28.8.2  nathanw 				      (char *)finfo;
   1028  1.28.8.2  nathanw 
   1029  1.28.8.2  nathanw 		type  = fd->sc_type;
   1030  1.28.8.2  nathanw 		sec   = fd->sc_blkno % type->seccyl;
   1031  1.28.8.2  nathanw 		head  = sec / type->sectrac;
   1032  1.28.8.2  nathanw 		sec  -= head * type->sectrac;
   1033  1.28.8.2  nathanw 		nblks = type->sectrac - sec;
   1034  1.28.8.2  nathanw 		nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
   1035  1.28.8.2  nathanw 		nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
   1036  1.28.8.2  nathanw 		fd->sc_nblks  = nblks;
   1037  1.28.8.2  nathanw 		fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
   1038  1.28.8.2  nathanw #ifdef DIAGNOSTIC
   1039  1.28.8.2  nathanw 		{
   1040  1.28.8.2  nathanw 		     int block;
   1041  1.28.8.2  nathanw 
   1042  1.28.8.2  nathanw 		     block = (fd->sc_cylin * type->heads + head)
   1043  1.28.8.2  nathanw 				* type->sectrac + sec;
   1044  1.28.8.2  nathanw 		     if (block != fd->sc_blkno) {
   1045  1.28.8.2  nathanw 			 printf("fdcintr: block %d != blkno %d\n",
   1046  1.28.8.2  nathanw 						block, fd->sc_blkno);
   1047  1.28.8.2  nathanw #ifdef DDB
   1048  1.28.8.2  nathanw 			 Debugger();
   1049  1.28.8.2  nathanw #endif
   1050  1.28.8.2  nathanw 		     }
   1051  1.28.8.2  nathanw 		}
   1052  1.28.8.2  nathanw #endif
   1053  1.28.8.2  nathanw 		read = bp->b_flags & B_READ ? 1 : 0;
   1054  1.28.8.2  nathanw 
   1055  1.28.8.2  nathanw 		/*
   1056  1.28.8.2  nathanw 		 * Setup pseudo-dma address & count
   1057  1.28.8.2  nathanw 		 */
   1058  1.28.8.2  nathanw 		fddmaaddr = bp->b_data + fd->sc_skip;
   1059  1.28.8.2  nathanw 		fddmalen  = fd->sc_nbytes;
   1060  1.28.8.2  nathanw 
   1061  1.28.8.2  nathanw 		wrt_fdc_reg(fdctl, type->rate);
   1062  1.28.8.2  nathanw #ifdef FD_DEBUG
   1063  1.28.8.2  nathanw 		printf("fdcintr: %s drive %d track %d head %d sec %d"
   1064  1.28.8.2  nathanw 			" nblks %d\n", read ? "read" : "write",
   1065  1.28.8.2  nathanw 			fd->sc_drive, fd->sc_cylin, head, sec, nblks);
   1066  1.28.8.2  nathanw #endif
   1067  1.28.8.2  nathanw 		fdc_ienable();
   1068  1.28.8.2  nathanw 
   1069  1.28.8.2  nathanw 		if (finfo) {
   1070  1.28.8.2  nathanw 			/* formatting */
   1071  1.28.8.2  nathanw 			if (out_fdc(NE7CMD_FORMAT) < 0) {
   1072  1.28.8.2  nathanw 				fdc->sc_errors = 4;
   1073  1.28.8.2  nathanw 				fdcretry(fdc);
   1074  1.28.8.2  nathanw 				goto loop;
   1075  1.28.8.2  nathanw 			}
   1076  1.28.8.2  nathanw 			out_fdc((head << 2) | fd->sc_drive);
   1077  1.28.8.2  nathanw 			out_fdc(finfo->fd_formb_secshift);
   1078  1.28.8.2  nathanw 			out_fdc(finfo->fd_formb_nsecs);
   1079  1.28.8.2  nathanw 			out_fdc(finfo->fd_formb_gaplen);
   1080  1.28.8.2  nathanw 			out_fdc(finfo->fd_formb_fillbyte);
   1081  1.28.8.2  nathanw 		} else {
   1082  1.28.8.2  nathanw 			if (read)
   1083  1.28.8.2  nathanw 				out_fdc(NE7CMD_READ);	/* READ */
   1084  1.28.8.2  nathanw 			else
   1085  1.28.8.2  nathanw 				out_fdc(NE7CMD_WRITE);	/* WRITE */
   1086  1.28.8.2  nathanw 			out_fdc((head << 2) | fd->sc_drive);
   1087  1.28.8.2  nathanw 			out_fdc(fd->sc_cylin);		/* track	 */
   1088  1.28.8.2  nathanw 			out_fdc(head);			/* head		 */
   1089  1.28.8.2  nathanw 			out_fdc(sec + 1);		/* sector +1	 */
   1090  1.28.8.2  nathanw 			out_fdc(type->secsize);		/* sector size   */
   1091  1.28.8.2  nathanw 			out_fdc(sec + nblks);		/* last sectors	 */
   1092  1.28.8.2  nathanw 			out_fdc(type->gap1);		/* gap1 size	 */
   1093  1.28.8.2  nathanw 			out_fdc(type->datalen);		/* data length	 */
   1094  1.28.8.2  nathanw 		}
   1095  1.28.8.2  nathanw 		fdc->sc_state = IOCOMPLETE;
   1096  1.28.8.2  nathanw 
   1097  1.28.8.2  nathanw 		disk_busy(&fd->sc_dk);
   1098  1.28.8.2  nathanw 
   1099  1.28.8.2  nathanw 		/* allow 2 seconds for operation */
   1100  1.28.8.2  nathanw 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1101  1.28.8.2  nathanw 		return 1;				/* will return later */
   1102  1.28.8.2  nathanw 
   1103  1.28.8.2  nathanw 	case SEEKWAIT:
   1104  1.28.8.2  nathanw 		callout_stop(&fdc->sc_timo_ch);
   1105  1.28.8.2  nathanw 		fdc->sc_state = SEEKCOMPLETE;
   1106  1.28.8.2  nathanw 		/* allow 1/50 second for heads to settle */
   1107  1.28.8.2  nathanw 		callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
   1108  1.28.8.2  nathanw 		return 1;
   1109  1.28.8.2  nathanw 
   1110  1.28.8.2  nathanw 	case SEEKCOMPLETE:
   1111  1.28.8.6  nathanw 		/* no data on seek */
   1112  1.28.8.6  nathanw 		disk_unbusy(&fd->sc_dk, 0, 0);
   1113  1.28.8.2  nathanw 
   1114  1.28.8.2  nathanw 		/* Make sure seek really happened. */
   1115  1.28.8.2  nathanw 		out_fdc(NE7CMD_SENSEI);
   1116  1.28.8.2  nathanw 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
   1117  1.28.8.2  nathanw 		    cyl != bp->b_cylinder * fd->sc_type->step) {
   1118  1.28.8.2  nathanw #ifdef FD_DEBUG
   1119  1.28.8.2  nathanw 			fdcstatus(&fd->sc_dev, 2, "seek failed");
   1120  1.28.8.2  nathanw #endif
   1121  1.28.8.2  nathanw 			fdcretry(fdc);
   1122  1.28.8.2  nathanw 			goto loop;
   1123  1.28.8.2  nathanw 		}
   1124  1.28.8.2  nathanw 		fd->sc_cylin = bp->b_cylinder;
   1125  1.28.8.2  nathanw 		goto doio;
   1126  1.28.8.2  nathanw 
   1127  1.28.8.2  nathanw 	case IOTIMEDOUT:
   1128  1.28.8.2  nathanw 	case SEEKTIMEDOUT:
   1129  1.28.8.2  nathanw 	case RECALTIMEDOUT:
   1130  1.28.8.2  nathanw 	case RESETTIMEDOUT:
   1131  1.28.8.2  nathanw 		fdcretry(fdc);
   1132  1.28.8.2  nathanw 		goto loop;
   1133  1.28.8.2  nathanw 
   1134  1.28.8.2  nathanw 	case IOCOMPLETE: /* IO DONE, post-analyze */
   1135  1.28.8.2  nathanw 		callout_stop(&fdc->sc_timo_ch);
   1136  1.28.8.2  nathanw 
   1137  1.28.8.6  nathanw 		disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
   1138  1.28.8.6  nathanw 		    (bp->b_flags & B_READ));
   1139  1.28.8.2  nathanw 
   1140  1.28.8.2  nathanw 		if (fdcresult(fdc) != 7 || (st1 & 0x37) != 0) {
   1141  1.28.8.2  nathanw 			/*
   1142  1.28.8.2  nathanw 			 * As the damn chip doesn't seem to have a FIFO,
   1143  1.28.8.2  nathanw 			 * accept a few overruns as a fact of life *sigh*
   1144  1.28.8.2  nathanw 			 */
   1145  1.28.8.2  nathanw 			if ((st1 & 0x10) && (++fdc->sc_overruns < 4)) {
   1146  1.28.8.2  nathanw 				fdc->sc_state = DOSEEK;
   1147  1.28.8.2  nathanw 				goto loop;
   1148  1.28.8.2  nathanw 			}
   1149  1.28.8.2  nathanw #ifdef FD_DEBUG
   1150  1.28.8.2  nathanw 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
   1151  1.28.8.2  nathanw 			    "read failed" : "write failed");
   1152  1.28.8.2  nathanw 			printf("blkno %d nblks %d\n",
   1153  1.28.8.2  nathanw 			    fd->sc_blkno, fd->sc_nblks);
   1154  1.28.8.2  nathanw #endif
   1155  1.28.8.2  nathanw 			fdcretry(fdc);
   1156  1.28.8.2  nathanw 			goto loop;
   1157  1.28.8.2  nathanw 		}
   1158  1.28.8.2  nathanw 		if (fdc->sc_errors) {
   1159  1.28.8.2  nathanw 			diskerr(bp, "fd", "soft error", LOG_PRINTF,
   1160  1.28.8.2  nathanw 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
   1161  1.28.8.2  nathanw 			printf("\n");
   1162  1.28.8.2  nathanw 			fdc->sc_errors = 0;
   1163  1.28.8.2  nathanw 		}
   1164  1.28.8.2  nathanw 		fdc->sc_overruns = 0;
   1165  1.28.8.2  nathanw 		fd->sc_blkno += fd->sc_nblks;
   1166  1.28.8.2  nathanw 		fd->sc_skip += fd->sc_nbytes;
   1167  1.28.8.2  nathanw 		fd->sc_bcount -= fd->sc_nbytes;
   1168  1.28.8.2  nathanw 		if (!finfo && fd->sc_bcount > 0) {
   1169  1.28.8.2  nathanw 			bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
   1170  1.28.8.2  nathanw 			goto doseek;
   1171  1.28.8.2  nathanw 		}
   1172  1.28.8.2  nathanw 		fdfinish(fd, bp);
   1173  1.28.8.2  nathanw 		goto loop;
   1174  1.28.8.2  nathanw 
   1175  1.28.8.2  nathanw 	case DORESET:
   1176  1.28.8.2  nathanw 		/* try a reset, keep motor on */
   1177  1.28.8.2  nathanw 		fd_set_motor(fdc, 1);
   1178  1.28.8.2  nathanw 		delay(100);
   1179  1.28.8.2  nathanw 		fd_set_motor(fdc, 0);
   1180  1.28.8.2  nathanw 		fdc->sc_state = RESETCOMPLETE;
   1181  1.28.8.2  nathanw 		callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
   1182  1.28.8.2  nathanw 		return 1;			/* will return later */
   1183  1.28.8.2  nathanw 
   1184  1.28.8.2  nathanw 	case RESETCOMPLETE:
   1185  1.28.8.2  nathanw 		callout_stop(&fdc->sc_timo_ch);
   1186  1.28.8.2  nathanw 		/* clear the controller output buffer */
   1187  1.28.8.2  nathanw 		for (i = 0; i < 4; i++) {
   1188  1.28.8.2  nathanw 			out_fdc(NE7CMD_SENSEI);
   1189  1.28.8.2  nathanw 			(void) fdcresult(fdc);
   1190  1.28.8.2  nathanw 		}
   1191  1.28.8.2  nathanw 
   1192  1.28.8.2  nathanw 		/* fall through */
   1193  1.28.8.2  nathanw 	case DORECAL:
   1194  1.28.8.2  nathanw 		fdc_ienable();
   1195  1.28.8.2  nathanw 
   1196  1.28.8.2  nathanw 		out_fdc(NE7CMD_RECAL);	/* recalibrate function */
   1197  1.28.8.2  nathanw 		out_fdc(fd->sc_drive);
   1198  1.28.8.2  nathanw 		fdc->sc_state = RECALWAIT;
   1199  1.28.8.2  nathanw 		callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
   1200  1.28.8.2  nathanw 		return 1;			/* will return later */
   1201  1.28.8.2  nathanw 
   1202  1.28.8.2  nathanw 	case RECALWAIT:
   1203  1.28.8.2  nathanw 		callout_stop(&fdc->sc_timo_ch);
   1204  1.28.8.2  nathanw 		fdc->sc_state = RECALCOMPLETE;
   1205  1.28.8.2  nathanw 		/* allow 1/30 second for heads to settle */
   1206  1.28.8.2  nathanw 		callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
   1207  1.28.8.2  nathanw 		return 1;			/* will return later */
   1208  1.28.8.2  nathanw 
   1209  1.28.8.2  nathanw 	case RECALCOMPLETE:
   1210  1.28.8.2  nathanw 		out_fdc(NE7CMD_SENSEI);
   1211  1.28.8.2  nathanw 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
   1212  1.28.8.2  nathanw #ifdef FD_DEBUG
   1213  1.28.8.2  nathanw 			fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
   1214  1.28.8.2  nathanw #endif
   1215  1.28.8.2  nathanw 			fdcretry(fdc);
   1216  1.28.8.2  nathanw 			goto loop;
   1217  1.28.8.2  nathanw 		}
   1218  1.28.8.2  nathanw 		fd->sc_cylin = 0;
   1219  1.28.8.2  nathanw 		goto doseek;
   1220  1.28.8.2  nathanw 
   1221  1.28.8.2  nathanw 	case MOTORWAIT:
   1222  1.28.8.2  nathanw 		if (fd->sc_flags & FD_MOTOR_WAIT)
   1223  1.28.8.2  nathanw 			return 1;		/* time's not up yet */
   1224  1.28.8.2  nathanw 		goto doseek;
   1225  1.28.8.2  nathanw 
   1226  1.28.8.2  nathanw 	default:
   1227  1.28.8.2  nathanw 		fdcstatus(&fd->sc_dev, 0, "stray interrupt");
   1228  1.28.8.2  nathanw 		return 1;
   1229  1.28.8.2  nathanw 	}
   1230  1.28.8.2  nathanw #ifdef DIAGNOSTIC
   1231  1.28.8.2  nathanw 	panic("fdcintr: impossible");
   1232  1.28.8.2  nathanw #endif
   1233  1.28.8.2  nathanw #undef	st0
   1234  1.28.8.2  nathanw #undef	st1
   1235  1.28.8.2  nathanw #undef	cyl
   1236  1.28.8.2  nathanw }
   1237  1.28.8.2  nathanw 
   1238  1.28.8.2  nathanw void
   1239  1.28.8.2  nathanw fdcretry(fdc)
   1240  1.28.8.2  nathanw 	struct fdc_softc *fdc;
   1241  1.28.8.2  nathanw {
   1242  1.28.8.2  nathanw 	char bits[64];
   1243  1.28.8.2  nathanw 	struct fd_softc *fd;
   1244  1.28.8.2  nathanw 	struct buf *bp;
   1245  1.28.8.2  nathanw 
   1246  1.28.8.2  nathanw 	fd = fdc->sc_drives.tqh_first;
   1247  1.28.8.3  nathanw 	bp = BUFQ_PEEK(&fd->sc_q);
   1248  1.28.8.2  nathanw 
   1249  1.28.8.2  nathanw 	if (fd->sc_opts & FDOPT_NORETRY)
   1250  1.28.8.2  nathanw 	    goto fail;
   1251  1.28.8.2  nathanw 
   1252  1.28.8.2  nathanw 	switch (fdc->sc_errors) {
   1253  1.28.8.2  nathanw 	case 0:
   1254  1.28.8.2  nathanw 		/* try again */
   1255  1.28.8.2  nathanw 		fdc->sc_state = DOSEEK;
   1256  1.28.8.2  nathanw 		break;
   1257  1.28.8.2  nathanw 
   1258  1.28.8.2  nathanw 	case 1: case 2: case 3:
   1259  1.28.8.2  nathanw 		/* didn't work; try recalibrating */
   1260  1.28.8.2  nathanw 		fdc->sc_state = DORECAL;
   1261  1.28.8.2  nathanw 		break;
   1262  1.28.8.2  nathanw 
   1263  1.28.8.2  nathanw 	case 4:
   1264  1.28.8.2  nathanw 		/* still no go; reset the bastard */
   1265  1.28.8.2  nathanw 		fdc->sc_state = DORESET;
   1266  1.28.8.2  nathanw 		break;
   1267  1.28.8.2  nathanw 
   1268  1.28.8.2  nathanw 	default:
   1269  1.28.8.2  nathanw 	fail:
   1270  1.28.8.2  nathanw 		if ((fd->sc_opts & FDOPT_SILENT) == 0) {
   1271  1.28.8.2  nathanw 			diskerr(bp, "fd", "hard error", LOG_PRINTF,
   1272  1.28.8.2  nathanw 				fd->sc_skip / FDC_BSIZE,
   1273  1.28.8.2  nathanw 				(struct disklabel *)NULL);
   1274  1.28.8.2  nathanw 
   1275  1.28.8.2  nathanw 			printf(" (st0 %s",
   1276  1.28.8.2  nathanw 			       bitmask_snprintf(fdc->sc_status[0],
   1277  1.28.8.2  nathanw 						NE7_ST0BITS, bits,
   1278  1.28.8.2  nathanw 						sizeof(bits)));
   1279  1.28.8.2  nathanw 			printf(" st1 %s",
   1280  1.28.8.2  nathanw 			       bitmask_snprintf(fdc->sc_status[1],
   1281  1.28.8.2  nathanw 						NE7_ST1BITS, bits,
   1282  1.28.8.2  nathanw 						sizeof(bits)));
   1283  1.28.8.2  nathanw 			printf(" st2 %s",
   1284  1.28.8.2  nathanw 			       bitmask_snprintf(fdc->sc_status[2],
   1285  1.28.8.2  nathanw 						NE7_ST2BITS, bits,
   1286  1.28.8.2  nathanw 						sizeof(bits)));
   1287  1.28.8.2  nathanw 			printf(" cyl %d head %d sec %d)\n",
   1288  1.28.8.2  nathanw 			       fdc->sc_status[3],
   1289  1.28.8.2  nathanw 			       fdc->sc_status[4],
   1290  1.28.8.2  nathanw 			       fdc->sc_status[5]);
   1291  1.28.8.2  nathanw 		}
   1292  1.28.8.2  nathanw 		bp->b_flags |= B_ERROR;
   1293  1.28.8.2  nathanw 		bp->b_error = EIO;
   1294  1.28.8.2  nathanw 		fdfinish(fd, bp);
   1295  1.28.8.2  nathanw 	}
   1296  1.28.8.2  nathanw 	fdc->sc_errors++;
   1297  1.28.8.2  nathanw }
   1298  1.28.8.2  nathanw 
   1299  1.28.8.2  nathanw int
   1300  1.28.8.2  nathanw fdioctl(dev, cmd, addr, flag, p)
   1301  1.28.8.2  nathanw 	dev_t dev;
   1302  1.28.8.2  nathanw 	u_long cmd;
   1303  1.28.8.2  nathanw 	caddr_t addr;
   1304  1.28.8.2  nathanw 	int flag;
   1305  1.28.8.2  nathanw 	struct proc *p;
   1306  1.28.8.2  nathanw {
   1307  1.28.8.2  nathanw 	struct fd_softc		*fd;
   1308  1.28.8.2  nathanw 	struct disklabel	buffer;
   1309  1.28.8.2  nathanw 	int			error;
   1310  1.28.8.2  nathanw 	struct fdformat_parms	*form_parms;
   1311  1.28.8.2  nathanw 	struct fdformat_cmd	*form_cmd;
   1312  1.28.8.2  nathanw 	struct ne7_fd_formb	*fd_formb;
   1313  1.28.8.2  nathanw 	unsigned int		scratch;
   1314  1.28.8.2  nathanw 	int			il[FD_MAX_NSEC + 1];
   1315  1.28.8.2  nathanw 	register int		i, j;
   1316  1.28.8.2  nathanw 
   1317  1.28.8.2  nathanw 	fd = hdfd_cd.cd_devs[FDUNIT(dev)];
   1318  1.28.8.2  nathanw 
   1319  1.28.8.2  nathanw 	switch (cmd) {
   1320  1.28.8.2  nathanw 	case DIOCGDINFO:
   1321  1.28.8.2  nathanw 		fdgetdisklabel(fd, dev);
   1322  1.28.8.2  nathanw 		*(struct disklabel *)addr = *(fd->sc_dk.dk_label);
   1323  1.28.8.2  nathanw 		return 0;
   1324  1.28.8.2  nathanw 
   1325  1.28.8.2  nathanw 	case DIOCGPART:
   1326  1.28.8.2  nathanw 		fdgetdisklabel(fd, dev);
   1327  1.28.8.2  nathanw 		((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
   1328  1.28.8.2  nathanw 		((struct partinfo *)addr)->part =
   1329  1.28.8.2  nathanw 			      &fd->sc_dk.dk_label->d_partitions[RAW_PART];
   1330  1.28.8.2  nathanw 		return(0);
   1331  1.28.8.2  nathanw 
   1332  1.28.8.2  nathanw 	case DIOCWLABEL:
   1333  1.28.8.2  nathanw 		if ((flag & FWRITE) == 0)
   1334  1.28.8.2  nathanw 			return EBADF;
   1335  1.28.8.2  nathanw 		/* XXX do something */
   1336  1.28.8.2  nathanw 		return 0;
   1337  1.28.8.2  nathanw 
   1338  1.28.8.2  nathanw 	case DIOCSDINFO:
   1339  1.28.8.2  nathanw 	case DIOCWDINFO:
   1340  1.28.8.2  nathanw 		if ((flag & FWRITE) == 0)
   1341  1.28.8.2  nathanw 		    return EBADF;
   1342  1.28.8.2  nathanw 
   1343  1.28.8.2  nathanw 		fd->sc_flags &= ~FD_HAVELAB;   /* Invalid */
   1344  1.28.8.2  nathanw 		error = setdisklabel(&buffer, (struct disklabel *)addr, 0,NULL);
   1345  1.28.8.2  nathanw 		if (error)
   1346  1.28.8.2  nathanw 		    return error;
   1347  1.28.8.2  nathanw 
   1348  1.28.8.2  nathanw 		if (cmd == DIOCWDINFO)
   1349  1.28.8.2  nathanw 		    error = writedisklabel(dev, fdstrategy, &buffer, NULL);
   1350  1.28.8.2  nathanw 		return error;
   1351  1.28.8.2  nathanw 
   1352  1.28.8.2  nathanw 	case FDIOCGETFORMAT:
   1353  1.28.8.2  nathanw 		form_parms = (struct fdformat_parms *)addr;
   1354  1.28.8.2  nathanw 		form_parms->fdformat_version = FDFORMAT_VERSION;
   1355  1.28.8.2  nathanw 		form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
   1356  1.28.8.2  nathanw 		form_parms->ncyl = fd->sc_type->tracks;
   1357  1.28.8.2  nathanw 		form_parms->nspt = fd->sc_type->sectrac;
   1358  1.28.8.2  nathanw 		form_parms->ntrk = fd->sc_type->heads;
   1359  1.28.8.2  nathanw 		form_parms->stepspercyl = fd->sc_type->step;
   1360  1.28.8.2  nathanw 		form_parms->gaplen = fd->sc_type->gap2;
   1361  1.28.8.2  nathanw 		form_parms->fillbyte = fd->sc_type->fillbyte;
   1362  1.28.8.2  nathanw 		form_parms->interleave = fd->sc_type->interleave;
   1363  1.28.8.2  nathanw 		switch (fd->sc_type->rate) {
   1364  1.28.8.2  nathanw 		case FDC_500KBPS:
   1365  1.28.8.2  nathanw 			form_parms->xfer_rate = 500 * 1024;
   1366  1.28.8.2  nathanw 			break;
   1367  1.28.8.2  nathanw 		case FDC_300KBPS:
   1368  1.28.8.2  nathanw 			form_parms->xfer_rate = 300 * 1024;
   1369  1.28.8.2  nathanw 			break;
   1370  1.28.8.2  nathanw 		case FDC_250KBPS:
   1371  1.28.8.2  nathanw 			form_parms->xfer_rate = 250 * 1024;
   1372  1.28.8.2  nathanw 			break;
   1373  1.28.8.2  nathanw 		case FDC_125KBPS:
   1374  1.28.8.2  nathanw 			form_parms->xfer_rate = 125 * 1024;
   1375  1.28.8.2  nathanw 			break;
   1376  1.28.8.2  nathanw 		default:
   1377  1.28.8.2  nathanw 			return EINVAL;
   1378  1.28.8.2  nathanw 		}
   1379  1.28.8.2  nathanw 		return 0;
   1380  1.28.8.2  nathanw 
   1381  1.28.8.2  nathanw 	case FDIOCSETFORMAT:
   1382  1.28.8.2  nathanw 		if((flag & FWRITE) == 0)
   1383  1.28.8.2  nathanw 			return EBADF;	/* must be opened for writing */
   1384  1.28.8.2  nathanw 		form_parms = (struct fdformat_parms *)addr;
   1385  1.28.8.2  nathanw 		if (form_parms->fdformat_version != FDFORMAT_VERSION)
   1386  1.28.8.2  nathanw 			return EINVAL;	/* wrong version of formatting prog */
   1387  1.28.8.2  nathanw 
   1388  1.28.8.2  nathanw 		scratch = form_parms->nbps >> 7;
   1389  1.28.8.2  nathanw 		if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
   1390  1.28.8.2  nathanw 		    scratch & ~(1 << (ffs(scratch)-1)))
   1391  1.28.8.2  nathanw 			/* not a power-of-two multiple of 128 */
   1392  1.28.8.2  nathanw 			return EINVAL;
   1393  1.28.8.2  nathanw 
   1394  1.28.8.2  nathanw 		switch (form_parms->xfer_rate) {
   1395  1.28.8.2  nathanw 		case 500 * 1024:
   1396  1.28.8.2  nathanw 			fd->sc_type->rate = FDC_500KBPS;
   1397  1.28.8.2  nathanw 			break;
   1398  1.28.8.2  nathanw 		case 300 * 1024:
   1399  1.28.8.2  nathanw 			fd->sc_type->rate = FDC_300KBPS;
   1400  1.28.8.2  nathanw 			break;
   1401  1.28.8.2  nathanw 		case 250 * 1024:
   1402  1.28.8.2  nathanw 			fd->sc_type->rate = FDC_250KBPS;
   1403  1.28.8.2  nathanw 			break;
   1404  1.28.8.2  nathanw 		case 125 * 1024:
   1405  1.28.8.2  nathanw 			fd->sc_type->rate = FDC_125KBPS;
   1406  1.28.8.2  nathanw 			break;
   1407  1.28.8.2  nathanw 		default:
   1408  1.28.8.2  nathanw 			return EINVAL;
   1409  1.28.8.2  nathanw 		}
   1410  1.28.8.2  nathanw 
   1411  1.28.8.2  nathanw 		if (form_parms->nspt > FD_MAX_NSEC ||
   1412  1.28.8.2  nathanw 		    form_parms->fillbyte > 0xff ||
   1413  1.28.8.2  nathanw 		    form_parms->interleave > 0xff)
   1414  1.28.8.2  nathanw 			return EINVAL;
   1415  1.28.8.2  nathanw 		fd->sc_type->sectrac = form_parms->nspt;
   1416  1.28.8.2  nathanw 		if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
   1417  1.28.8.2  nathanw 			return EINVAL;
   1418  1.28.8.2  nathanw 		fd->sc_type->heads = form_parms->ntrk;
   1419  1.28.8.2  nathanw 		fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
   1420  1.28.8.2  nathanw 		fd->sc_type->secsize = ffs(scratch)-1;
   1421  1.28.8.2  nathanw 		fd->sc_type->gap2 = form_parms->gaplen;
   1422  1.28.8.2  nathanw 		fd->sc_type->tracks = form_parms->ncyl;
   1423  1.28.8.2  nathanw 		fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
   1424  1.28.8.2  nathanw 			form_parms->nbps / DEV_BSIZE;
   1425  1.28.8.2  nathanw 		fd->sc_type->step = form_parms->stepspercyl;
   1426  1.28.8.2  nathanw 		fd->sc_type->fillbyte = form_parms->fillbyte;
   1427  1.28.8.2  nathanw 		fd->sc_type->interleave = form_parms->interleave;
   1428  1.28.8.2  nathanw 		return 0;
   1429  1.28.8.2  nathanw 
   1430  1.28.8.2  nathanw 	case FDIOCFORMAT_TRACK:
   1431  1.28.8.2  nathanw 		if((flag & FWRITE) == 0)
   1432  1.28.8.2  nathanw 			return EBADF;	/* must be opened for writing */
   1433  1.28.8.2  nathanw 		form_cmd = (struct fdformat_cmd *)addr;
   1434  1.28.8.2  nathanw 		if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
   1435  1.28.8.2  nathanw 			return EINVAL;	/* wrong version of formatting prog */
   1436  1.28.8.2  nathanw 
   1437  1.28.8.2  nathanw 		if (form_cmd->head >= fd->sc_type->heads ||
   1438  1.28.8.2  nathanw 		    form_cmd->cylinder >= fd->sc_type->tracks) {
   1439  1.28.8.2  nathanw 			return EINVAL;
   1440  1.28.8.2  nathanw 		}
   1441  1.28.8.2  nathanw 
   1442  1.28.8.2  nathanw 		fd_formb = malloc(sizeof(struct ne7_fd_formb),
   1443  1.28.8.2  nathanw 		    M_TEMP, M_NOWAIT);
   1444  1.28.8.2  nathanw 		if (fd_formb == 0)
   1445  1.28.8.2  nathanw 			return ENOMEM;
   1446  1.28.8.2  nathanw 
   1447  1.28.8.2  nathanw 		fd_formb->head = form_cmd->head;
   1448  1.28.8.2  nathanw 		fd_formb->cyl = form_cmd->cylinder;
   1449  1.28.8.2  nathanw 		fd_formb->transfer_rate = fd->sc_type->rate;
   1450  1.28.8.2  nathanw 		fd_formb->fd_formb_secshift = fd->sc_type->secsize;
   1451  1.28.8.2  nathanw 		fd_formb->fd_formb_nsecs = fd->sc_type->sectrac;
   1452  1.28.8.2  nathanw 		fd_formb->fd_formb_gaplen = fd->sc_type->gap2;
   1453  1.28.8.2  nathanw 		fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte;
   1454  1.28.8.2  nathanw 
   1455  1.28.8.2  nathanw 		bzero(il,sizeof il);
   1456  1.28.8.2  nathanw 		for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) {
   1457  1.28.8.2  nathanw 			while (il[(j%fd_formb->fd_formb_nsecs)+1])
   1458  1.28.8.2  nathanw 				j++;
   1459  1.28.8.2  nathanw 			il[(j%fd_formb->fd_formb_nsecs)+1] = i;
   1460  1.28.8.2  nathanw 			j += fd->sc_type->interleave;
   1461  1.28.8.2  nathanw 		}
   1462  1.28.8.2  nathanw 		for (i = 0; i < fd_formb->fd_formb_nsecs; i++) {
   1463  1.28.8.2  nathanw 			fd_formb->fd_formb_cylno(i) = form_cmd->cylinder;
   1464  1.28.8.2  nathanw 			fd_formb->fd_formb_headno(i) = form_cmd->head;
   1465  1.28.8.2  nathanw 			fd_formb->fd_formb_secno(i) = il[i+1];
   1466  1.28.8.2  nathanw 			fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize;
   1467  1.28.8.2  nathanw 		}
   1468  1.28.8.2  nathanw 
   1469  1.28.8.2  nathanw 		error = fdformat(dev, fd_formb, p);
   1470  1.28.8.2  nathanw 		free(fd_formb, M_TEMP);
   1471  1.28.8.2  nathanw 		return error;
   1472  1.28.8.2  nathanw 
   1473  1.28.8.2  nathanw 	case FDIOCGETOPTS:		/* get drive options */
   1474  1.28.8.2  nathanw 		*(int *)addr = fd->sc_opts;
   1475  1.28.8.2  nathanw 		return 0;
   1476  1.28.8.2  nathanw 
   1477  1.28.8.2  nathanw 	case FDIOCSETOPTS:		/* set drive options */
   1478  1.28.8.2  nathanw 		fd->sc_opts = *(int *)addr;
   1479  1.28.8.2  nathanw 		return 0;
   1480  1.28.8.2  nathanw 
   1481  1.28.8.2  nathanw 
   1482  1.28.8.2  nathanw 	default:
   1483  1.28.8.2  nathanw 		return ENOTTY;
   1484  1.28.8.2  nathanw 	}
   1485  1.28.8.2  nathanw 
   1486  1.28.8.2  nathanw #ifdef DIAGNOSTIC
   1487  1.28.8.2  nathanw 	panic("fdioctl: impossible");
   1488  1.28.8.2  nathanw #endif
   1489  1.28.8.2  nathanw }
   1490  1.28.8.2  nathanw 
   1491  1.28.8.2  nathanw int
   1492  1.28.8.2  nathanw fdformat(dev, finfo, p)
   1493  1.28.8.2  nathanw 	dev_t dev;
   1494  1.28.8.2  nathanw 	struct ne7_fd_formb *finfo;
   1495  1.28.8.2  nathanw 	struct proc *p;
   1496  1.28.8.2  nathanw {
   1497  1.28.8.2  nathanw 	int rv = 0, s;
   1498  1.28.8.2  nathanw 	struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(dev)];
   1499  1.28.8.2  nathanw 	struct fd_type *type = fd->sc_type;
   1500  1.28.8.2  nathanw 	struct buf *bp;
   1501  1.28.8.2  nathanw 
   1502  1.28.8.2  nathanw 	/* set up a buffer header for fdstrategy() */
   1503  1.28.8.2  nathanw 	bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
   1504  1.28.8.2  nathanw 	if(bp == 0)
   1505  1.28.8.2  nathanw 		return ENOBUFS;
   1506  1.28.8.2  nathanw 	bzero((void *)bp, sizeof(struct buf));
   1507  1.28.8.2  nathanw 	bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
   1508  1.28.8.2  nathanw 	bp->b_proc = p;
   1509  1.28.8.2  nathanw 	bp->b_dev = dev;
   1510  1.28.8.2  nathanw 
   1511  1.28.8.2  nathanw 	/*
   1512  1.28.8.2  nathanw 	 * calculate a fake blkno, so fdstrategy() would initiate a
   1513  1.28.8.2  nathanw 	 * seek to the requested cylinder
   1514  1.28.8.2  nathanw 	 */
   1515  1.28.8.2  nathanw 	bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
   1516  1.28.8.2  nathanw 		       + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
   1517  1.28.8.2  nathanw 
   1518  1.28.8.2  nathanw 	bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
   1519  1.28.8.2  nathanw 	bp->b_data = (caddr_t)finfo;
   1520  1.28.8.2  nathanw 
   1521  1.28.8.2  nathanw #ifdef DEBUG
   1522  1.28.8.2  nathanw 	printf("fdformat: blkno %x count %lx\n", bp->b_blkno, bp->b_bcount);
   1523  1.28.8.2  nathanw #endif
   1524  1.28.8.2  nathanw 
   1525  1.28.8.2  nathanw 	/* now do the format */
   1526  1.28.8.2  nathanw 	fdstrategy(bp);
   1527  1.28.8.2  nathanw 
   1528  1.28.8.2  nathanw 	/* ...and wait for it to complete */
   1529  1.28.8.2  nathanw 	s = splbio();
   1530  1.28.8.2  nathanw 	while(!(bp->b_flags & B_DONE)) {
   1531  1.28.8.2  nathanw 		rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
   1532  1.28.8.2  nathanw 		if (rv == EWOULDBLOCK)
   1533  1.28.8.2  nathanw 			break;
   1534  1.28.8.2  nathanw 	}
   1535  1.28.8.2  nathanw 	splx(s);
   1536  1.28.8.2  nathanw 
   1537  1.28.8.2  nathanw 	if (rv == EWOULDBLOCK) {
   1538  1.28.8.2  nathanw 		/* timed out */
   1539  1.28.8.2  nathanw 		rv = EIO;
   1540  1.28.8.2  nathanw 		biodone(bp);
   1541  1.28.8.2  nathanw 	}
   1542  1.28.8.2  nathanw 	if(bp->b_flags & B_ERROR) {
   1543  1.28.8.2  nathanw 		rv = bp->b_error;
   1544  1.28.8.2  nathanw 	}
   1545  1.28.8.2  nathanw 	free(bp, M_TEMP);
   1546  1.28.8.2  nathanw 	return rv;
   1547  1.28.8.2  nathanw }
   1548  1.28.8.2  nathanw 
   1549  1.28.8.2  nathanw 
   1550  1.28.8.2  nathanw /*
   1551  1.28.8.2  nathanw  * Obtain a disklabel. Either a real one from the disk or, if there
   1552  1.28.8.2  nathanw  * is none, a fake one.
   1553  1.28.8.2  nathanw  */
   1554  1.28.8.2  nathanw static void
   1555  1.28.8.2  nathanw fdgetdisklabel(fd, dev)
   1556  1.28.8.2  nathanw struct fd_softc *fd;
   1557  1.28.8.2  nathanw dev_t		dev;
   1558  1.28.8.2  nathanw {
   1559  1.28.8.2  nathanw 	struct disklabel	*lp;
   1560  1.28.8.2  nathanw 	struct cpu_disklabel	cpulab;
   1561  1.28.8.2  nathanw 
   1562  1.28.8.2  nathanw 	if (fd->sc_flags & FD_HAVELAB)
   1563  1.28.8.2  nathanw 		return; /* Already got one */
   1564  1.28.8.2  nathanw 
   1565  1.28.8.2  nathanw 	lp   = fd->sc_dk.dk_label;
   1566  1.28.8.2  nathanw 
   1567  1.28.8.2  nathanw 	bzero(lp, sizeof(*lp));
   1568  1.28.8.2  nathanw 	bzero(&cpulab, sizeof(cpulab));
   1569  1.28.8.2  nathanw 
   1570  1.28.8.2  nathanw 	lp->d_secpercyl  = fd->sc_type->seccyl;
   1571  1.28.8.2  nathanw 	lp->d_type       = DTYPE_FLOPPY;
   1572  1.28.8.2  nathanw 	lp->d_secsize    = FDC_BSIZE;
   1573  1.28.8.2  nathanw 	lp->d_secperunit = fd->sc_type->size;
   1574  1.28.8.2  nathanw 
   1575  1.28.8.2  nathanw 	/*
   1576  1.28.8.2  nathanw 	 * If there is no label on the disk: fake one
   1577  1.28.8.2  nathanw 	 */
   1578  1.28.8.2  nathanw 	if (readdisklabel(dev, fdstrategy, lp, &cpulab) != NULL)
   1579  1.28.8.2  nathanw 		fdgetdefaultlabel(fd, lp, RAW_PART);
   1580  1.28.8.2  nathanw 	fd->sc_flags |= FD_HAVELAB;
   1581  1.28.8.2  nathanw 
   1582  1.28.8.2  nathanw 	if ((FDC_BSIZE * fd->sc_type->size)
   1583  1.28.8.2  nathanw 		< (lp->d_secsize * lp->d_secperunit)) {
   1584  1.28.8.2  nathanw 		/*
   1585  1.28.8.2  nathanw 		 * XXX: Ignore these fields. If you drop a vnddisk
   1586  1.28.8.2  nathanw 		 *	on more than one floppy, you'll get disturbing
   1587  1.28.8.2  nathanw 		 *	sounds!
   1588  1.28.8.2  nathanw 		 */
   1589  1.28.8.2  nathanw 		lp->d_secpercyl  = fd->sc_type->seccyl;
   1590  1.28.8.2  nathanw 		lp->d_type       = DTYPE_FLOPPY;
   1591  1.28.8.2  nathanw 		lp->d_secsize    = FDC_BSIZE;
   1592  1.28.8.2  nathanw 		lp->d_secperunit = fd->sc_type->size;
   1593  1.28.8.2  nathanw 	}
   1594  1.28.8.2  nathanw }
   1595  1.28.8.2  nathanw 
   1596  1.28.8.2  nathanw /*
   1597  1.28.8.2  nathanw  * Build defaultdisk label. For now we only create a label from what we
   1598  1.28.8.2  nathanw  * know from 'sc'.
   1599  1.28.8.2  nathanw  */
   1600  1.28.8.2  nathanw static void
   1601  1.28.8.2  nathanw fdgetdefaultlabel(fd, lp, part)
   1602  1.28.8.2  nathanw 	struct fd_softc  *fd;
   1603  1.28.8.2  nathanw 	struct disklabel *lp;
   1604  1.28.8.2  nathanw 	int part;
   1605  1.28.8.2  nathanw {
   1606  1.28.8.2  nathanw 	bzero(lp, sizeof(struct disklabel));
   1607  1.28.8.2  nathanw 
   1608  1.28.8.2  nathanw 	lp->d_secsize     = 128 * (1 << fd->sc_type->secsize);
   1609  1.28.8.2  nathanw 	lp->d_ntracks     = fd->sc_type->heads;
   1610  1.28.8.2  nathanw 	lp->d_nsectors    = fd->sc_type->sectrac;
   1611  1.28.8.2  nathanw 	lp->d_secpercyl   = lp->d_ntracks * lp->d_nsectors;
   1612  1.28.8.2  nathanw 	lp->d_ncylinders  = fd->sc_type->size / lp->d_secpercyl;
   1613  1.28.8.2  nathanw 	lp->d_secperunit  = fd->sc_type->size;
   1614  1.28.8.2  nathanw 
   1615  1.28.8.2  nathanw 	lp->d_type        = DTYPE_FLOPPY;
   1616  1.28.8.2  nathanw 	lp->d_rpm         = 300; 	/* good guess I suppose.	*/
   1617  1.28.8.2  nathanw 	lp->d_interleave  = 1;		/* FIXME: is this OK?		*/
   1618  1.28.8.2  nathanw 	lp->d_bbsize      = 0;
   1619  1.28.8.2  nathanw 	lp->d_sbsize      = 0;
   1620  1.28.8.2  nathanw 	lp->d_npartitions = part + 1;
   1621  1.28.8.2  nathanw 	lp->d_trkseek     = 6000; 	/* Who cares...			*/
   1622  1.28.8.2  nathanw 	lp->d_magic       = DISKMAGIC;
   1623  1.28.8.2  nathanw 	lp->d_magic2      = DISKMAGIC;
   1624  1.28.8.2  nathanw 	lp->d_checksum    = dkcksum(lp);
   1625  1.28.8.2  nathanw 	lp->d_partitions[part].p_size   = lp->d_secperunit;
   1626  1.28.8.2  nathanw 	lp->d_partitions[part].p_fstype = FS_UNUSED;
   1627  1.28.8.2  nathanw 	lp->d_partitions[part].p_fsize  = 1024;
   1628  1.28.8.2  nathanw 	lp->d_partitions[part].p_frag   = 8;
   1629  1.28.8.2  nathanw }
   1630