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