Home | History | Annotate | Line # | Download | only in dev
fd.c revision 1.37.8.6
      1  1.37.8.6  nathanw /*	$NetBSD: fd.c,v 1.37.8.6 2002/10/18 02:40:44 nathanw Exp $	*/
      2  1.37.8.2  nathanw 
      3  1.37.8.2  nathanw /*-
      4  1.37.8.2  nathanw  * Copyright (c) 1998 The NetBSD Foundation, Inc.
      5  1.37.8.2  nathanw  * All rights reserved.
      6  1.37.8.2  nathanw  *
      7  1.37.8.2  nathanw  * This code is derived from software contributed to The NetBSD Foundation
      8  1.37.8.2  nathanw  * by Charles M. Hannum and Minoura Makoto.
      9  1.37.8.2  nathanw  *
     10  1.37.8.2  nathanw  * Redistribution and use in source and binary forms, with or without
     11  1.37.8.2  nathanw  * modification, are permitted provided that the following conditions
     12  1.37.8.2  nathanw  * are met:
     13  1.37.8.2  nathanw  * 1. Redistributions of source code must retain the above copyright
     14  1.37.8.2  nathanw  *    notice, this list of conditions and the following disclaimer.
     15  1.37.8.2  nathanw  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.37.8.2  nathanw  *    notice, this list of conditions and the following disclaimer in the
     17  1.37.8.2  nathanw  *    documentation and/or other materials provided with the distribution.
     18  1.37.8.2  nathanw  * 3. All advertising materials mentioning features or use of this software
     19  1.37.8.2  nathanw  *    must display the following acknowledgement:
     20  1.37.8.2  nathanw  *        This product includes software developed by the NetBSD
     21  1.37.8.2  nathanw  *        Foundation, Inc. and its contributors.
     22  1.37.8.2  nathanw  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  1.37.8.2  nathanw  *    contributors may be used to endorse or promote products derived
     24  1.37.8.2  nathanw  *    from this software without specific prior written permission.
     25  1.37.8.2  nathanw  *
     26  1.37.8.2  nathanw  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  1.37.8.2  nathanw  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  1.37.8.2  nathanw  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  1.37.8.2  nathanw  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  1.37.8.2  nathanw  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  1.37.8.2  nathanw  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  1.37.8.2  nathanw  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  1.37.8.2  nathanw  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  1.37.8.2  nathanw  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  1.37.8.2  nathanw  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  1.37.8.2  nathanw  * POSSIBILITY OF SUCH DAMAGE.
     37  1.37.8.2  nathanw  */
     38  1.37.8.2  nathanw 
     39  1.37.8.2  nathanw /*-
     40  1.37.8.2  nathanw  * Copyright (c) 1990 The Regents of the University of California.
     41  1.37.8.2  nathanw  * All rights reserved.
     42  1.37.8.2  nathanw  *
     43  1.37.8.2  nathanw  * This code is derived from software contributed to Berkeley by
     44  1.37.8.2  nathanw  * Don Ahn.
     45  1.37.8.2  nathanw  *
     46  1.37.8.2  nathanw  * Redistribution and use in source and binary forms, with or without
     47  1.37.8.2  nathanw  * modification, are permitted provided that the following conditions
     48  1.37.8.2  nathanw  * are met:
     49  1.37.8.2  nathanw  * 1. Redistributions of source code must retain the above copyright
     50  1.37.8.2  nathanw  *    notice, this list of conditions and the following disclaimer.
     51  1.37.8.2  nathanw  * 2. Redistributions in binary form must reproduce the above copyright
     52  1.37.8.2  nathanw  *    notice, this list of conditions and the following disclaimer in the
     53  1.37.8.2  nathanw  *    documentation and/or other materials provided with the distribution.
     54  1.37.8.2  nathanw  * 3. All advertising materials mentioning features or use of this software
     55  1.37.8.2  nathanw  *    must display the following acknowledgement:
     56  1.37.8.2  nathanw  *	This product includes software developed by the University of
     57  1.37.8.2  nathanw  *	California, Berkeley and its contributors.
     58  1.37.8.2  nathanw  * 4. Neither the name of the University nor the names of its contributors
     59  1.37.8.2  nathanw  *    may be used to endorse or promote products derived from this software
     60  1.37.8.2  nathanw  *    without specific prior written permission.
     61  1.37.8.2  nathanw  *
     62  1.37.8.2  nathanw  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     63  1.37.8.2  nathanw  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     64  1.37.8.2  nathanw  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     65  1.37.8.2  nathanw  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     66  1.37.8.2  nathanw  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     67  1.37.8.2  nathanw  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     68  1.37.8.2  nathanw  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     69  1.37.8.2  nathanw  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     70  1.37.8.2  nathanw  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     71  1.37.8.2  nathanw  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     72  1.37.8.2  nathanw  * SUCH DAMAGE.
     73  1.37.8.2  nathanw  *
     74  1.37.8.2  nathanw  *	@(#)fd.c	7.4 (Berkeley) 5/25/91
     75  1.37.8.2  nathanw  */
     76  1.37.8.2  nathanw 
     77  1.37.8.2  nathanw #include "rnd.h"
     78  1.37.8.2  nathanw #include "opt_ddb.h"
     79  1.37.8.2  nathanw #include "opt_m680x0.h"
     80  1.37.8.2  nathanw 
     81  1.37.8.2  nathanw #include <sys/param.h>
     82  1.37.8.2  nathanw #include <sys/systm.h>
     83  1.37.8.2  nathanw #include <sys/callout.h>
     84  1.37.8.2  nathanw #include <sys/kernel.h>
     85  1.37.8.2  nathanw #include <sys/conf.h>
     86  1.37.8.2  nathanw #include <sys/file.h>
     87  1.37.8.2  nathanw #include <sys/stat.h>
     88  1.37.8.2  nathanw #include <sys/ioctl.h>
     89  1.37.8.2  nathanw #include <sys/malloc.h>
     90  1.37.8.2  nathanw #include <sys/device.h>
     91  1.37.8.2  nathanw #include <sys/disklabel.h>
     92  1.37.8.2  nathanw #include <sys/dkstat.h>
     93  1.37.8.2  nathanw #include <sys/disk.h>
     94  1.37.8.2  nathanw #include <sys/buf.h>
     95  1.37.8.2  nathanw #include <sys/uio.h>
     96  1.37.8.2  nathanw #include <sys/syslog.h>
     97  1.37.8.2  nathanw #include <sys/queue.h>
     98  1.37.8.2  nathanw #include <sys/fdio.h>
     99  1.37.8.2  nathanw #if NRND > 0
    100  1.37.8.2  nathanw #include <sys/rnd.h>
    101  1.37.8.2  nathanw #endif
    102  1.37.8.2  nathanw 
    103  1.37.8.2  nathanw #include <uvm/uvm_extern.h>
    104  1.37.8.2  nathanw 
    105  1.37.8.2  nathanw #include <machine/bus.h>
    106  1.37.8.2  nathanw #include <machine/cpu.h>
    107  1.37.8.2  nathanw 
    108  1.37.8.2  nathanw #include <arch/x68k/dev/intiovar.h>
    109  1.37.8.2  nathanw #include <arch/x68k/dev/dmacvar.h>
    110  1.37.8.2  nathanw #include <arch/x68k/dev/fdreg.h>
    111  1.37.8.2  nathanw #include <arch/x68k/dev/opmreg.h> /* for CT1 access */
    112  1.37.8.2  nathanw 
    113  1.37.8.2  nathanw #include "locators.h"
    114  1.37.8.2  nathanw 
    115  1.37.8.2  nathanw #ifdef FDDEBUG
    116  1.37.8.2  nathanw #define DPRINTF(x)      if (fddebug) printf x
    117  1.37.8.2  nathanw int     fddebug = 0;
    118  1.37.8.2  nathanw #else
    119  1.37.8.2  nathanw #define DPRINTF(x)
    120  1.37.8.2  nathanw #endif
    121  1.37.8.2  nathanw 
    122  1.37.8.2  nathanw #define FDUNIT(dev)	(minor(dev) / 8)
    123  1.37.8.2  nathanw #define FDTYPE(dev)	(minor(dev) % 8)
    124  1.37.8.2  nathanw 
    125  1.37.8.2  nathanw enum fdc_state {
    126  1.37.8.2  nathanw 	DEVIDLE = 0,
    127  1.37.8.2  nathanw 	MOTORWAIT,
    128  1.37.8.2  nathanw 	DOSEEK,
    129  1.37.8.2  nathanw 	SEEKWAIT,
    130  1.37.8.2  nathanw 	SEEKTIMEDOUT,
    131  1.37.8.2  nathanw 	SEEKCOMPLETE,
    132  1.37.8.2  nathanw 	DOIO,
    133  1.37.8.2  nathanw 	IOCOMPLETE,
    134  1.37.8.2  nathanw 	IOTIMEDOUT,
    135  1.37.8.2  nathanw 	DORESET,
    136  1.37.8.2  nathanw 	RESETCOMPLETE,
    137  1.37.8.2  nathanw 	RESETTIMEDOUT,
    138  1.37.8.2  nathanw 	DORECAL,
    139  1.37.8.2  nathanw 	RECALWAIT,
    140  1.37.8.2  nathanw 	RECALTIMEDOUT,
    141  1.37.8.2  nathanw 	RECALCOMPLETE,
    142  1.37.8.2  nathanw 	DOCOPY,
    143  1.37.8.2  nathanw 	DOIOHALF,
    144  1.37.8.2  nathanw 	COPYCOMPLETE,
    145  1.37.8.2  nathanw };
    146  1.37.8.2  nathanw 
    147  1.37.8.2  nathanw /* software state, per controller */
    148  1.37.8.2  nathanw struct fdc_softc {
    149  1.37.8.2  nathanw 	struct device sc_dev;		/* boilerplate */
    150  1.37.8.2  nathanw 
    151  1.37.8.2  nathanw 	bus_space_tag_t sc_iot;		/* intio i/o space identifier */
    152  1.37.8.2  nathanw 	bus_space_handle_t sc_ioh;	/* intio io handle */
    153  1.37.8.2  nathanw 
    154  1.37.8.2  nathanw 	struct callout sc_timo_ch;	/* timeout callout */
    155  1.37.8.2  nathanw 	struct callout sc_intr_ch;	/* pseudo-intr callout */
    156  1.37.8.2  nathanw 
    157  1.37.8.2  nathanw 	bus_dma_tag_t sc_dmat;		/* intio dma tag */
    158  1.37.8.2  nathanw 	bus_dmamap_t sc_dmamap;		/* dma map */
    159  1.37.8.2  nathanw 	u_int8_t *sc_addr;			/* physical address */
    160  1.37.8.2  nathanw 	struct dmac_channel_stat *sc_dmachan; /* intio dma channel */
    161  1.37.8.2  nathanw 	struct dmac_dma_xfer *sc_xfer;	/* dma transfer */
    162  1.37.8.2  nathanw 
    163  1.37.8.2  nathanw 	struct fd_softc *sc_fd[4];	/* pointers to children */
    164  1.37.8.2  nathanw 	TAILQ_HEAD(drivehead, fd_softc) sc_drives;
    165  1.37.8.2  nathanw 	enum fdc_state sc_state;
    166  1.37.8.2  nathanw 	int sc_errors;			/* number of retries so far */
    167  1.37.8.2  nathanw 	u_char sc_status[7];		/* copy of registers */
    168  1.37.8.2  nathanw } fdc_softc;
    169  1.37.8.2  nathanw 
    170  1.37.8.2  nathanw int fdcintr __P((void*));
    171  1.37.8.2  nathanw void fdcreset __P((struct fdc_softc *));
    172  1.37.8.2  nathanw 
    173  1.37.8.2  nathanw /* controller driver configuration */
    174  1.37.8.2  nathanw int fdcprobe __P((struct device *, struct cfdata *, void *));
    175  1.37.8.2  nathanw void fdcattach __P((struct device *, struct device *, void *));
    176  1.37.8.2  nathanw int fdprint __P((void *, const char *));
    177  1.37.8.2  nathanw 
    178  1.37.8.6  nathanw CFATTACH_DECL(fdc, sizeof(struct fdc_softc),
    179  1.37.8.6  nathanw     fdcprobe, fdcattach, NULL, NULL);
    180  1.37.8.2  nathanw 
    181  1.37.8.2  nathanw extern struct cfdriver fdc_cd;
    182  1.37.8.2  nathanw 
    183  1.37.8.2  nathanw /*
    184  1.37.8.2  nathanw  * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
    185  1.37.8.2  nathanw  * we tell them apart.
    186  1.37.8.2  nathanw  */
    187  1.37.8.2  nathanw struct fd_type {
    188  1.37.8.2  nathanw 	int	sectrac;	/* sectors per track */
    189  1.37.8.2  nathanw 	int	heads;		/* number of heads */
    190  1.37.8.2  nathanw 	int	seccyl;		/* sectors per cylinder */
    191  1.37.8.2  nathanw 	int	secsize;	/* size code for sectors */
    192  1.37.8.2  nathanw 	int	datalen;	/* data len when secsize = 0 */
    193  1.37.8.2  nathanw 	int	steprate;	/* step rate and head unload time */
    194  1.37.8.2  nathanw 	int	gap1;		/* gap len between sectors */
    195  1.37.8.2  nathanw 	int	gap2;		/* formatting gap */
    196  1.37.8.2  nathanw 	int	cyls;		/* total num of cylinders */
    197  1.37.8.2  nathanw 	int	size;		/* size of disk in sectors */
    198  1.37.8.2  nathanw 	int	step;		/* steps per cylinder */
    199  1.37.8.2  nathanw 	int	rate;		/* transfer speed code */
    200  1.37.8.2  nathanw 	char	*name;
    201  1.37.8.2  nathanw };
    202  1.37.8.2  nathanw 
    203  1.37.8.2  nathanw /* The order of entries in the following table is important -- BEWARE! */
    204  1.37.8.2  nathanw struct fd_type fd_types[] = {
    205  1.37.8.2  nathanw         {  8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, "1.2MB/[1024bytes/sector]"    }, /* 1.2 MB japanese format */
    206  1.37.8.2  nathanw         { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB"    }, /* 1.44MB diskette */
    207  1.37.8.2  nathanw         { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB"    }, /* 1.2 MB AT-diskettes */
    208  1.37.8.2  nathanw         {  9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */
    209  1.37.8.2  nathanw         {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
    210  1.37.8.2  nathanw         {  9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB"    }, /* 3.5" 720kB diskette */
    211  1.37.8.2  nathanw         {  9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x"  }, /* 720kB in 1.2MB drive */
    212  1.37.8.2  nathanw         {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x"  }, /* 360kB in 720kB drive */
    213  1.37.8.2  nathanw };
    214  1.37.8.2  nathanw 
    215  1.37.8.2  nathanw /* software state, per disk (with up to 4 disks per ctlr) */
    216  1.37.8.2  nathanw struct fd_softc {
    217  1.37.8.2  nathanw 	struct device sc_dev;
    218  1.37.8.2  nathanw 	struct disk sc_dk;
    219  1.37.8.2  nathanw 
    220  1.37.8.2  nathanw 	struct fd_type *sc_deftype;	/* default type descriptor */
    221  1.37.8.2  nathanw 	struct fd_type *sc_type;	/* current type descriptor */
    222  1.37.8.2  nathanw 
    223  1.37.8.2  nathanw 	struct callout sc_motoron_ch;
    224  1.37.8.2  nathanw 	struct callout sc_motoroff_ch;
    225  1.37.8.2  nathanw 
    226  1.37.8.2  nathanw 	daddr_t	sc_blkno;	/* starting block number */
    227  1.37.8.2  nathanw 	int sc_bcount;		/* byte count left */
    228  1.37.8.2  nathanw  	int sc_opts;			/* user-set options */
    229  1.37.8.2  nathanw 	int sc_skip;		/* bytes already transferred */
    230  1.37.8.2  nathanw 	int sc_nblks;		/* number of blocks currently transferring */
    231  1.37.8.2  nathanw 	int sc_nbytes;		/* number of bytes currently transferring */
    232  1.37.8.2  nathanw 
    233  1.37.8.2  nathanw 	int sc_drive;		/* physical unit number */
    234  1.37.8.2  nathanw 	int sc_flags;
    235  1.37.8.2  nathanw #define	FD_BOPEN	0x01		/* it's open */
    236  1.37.8.2  nathanw #define	FD_COPEN	0x02		/* it's open */
    237  1.37.8.2  nathanw #define	FD_OPEN		(FD_BOPEN|FD_COPEN)	/* it's open */
    238  1.37.8.2  nathanw #define	FD_MOTOR	0x04		/* motor should be on */
    239  1.37.8.2  nathanw #define	FD_MOTOR_WAIT	0x08		/* motor coming up */
    240  1.37.8.2  nathanw #define	FD_ALIVE	0x10		/* alive */
    241  1.37.8.2  nathanw 	int sc_cylin;		/* where we think the head is */
    242  1.37.8.2  nathanw 
    243  1.37.8.2  nathanw 	TAILQ_ENTRY(fd_softc) sc_drivechain;
    244  1.37.8.2  nathanw 	int sc_ops;		/* I/O ops since last switch */
    245  1.37.8.4  nathanw 	struct bufq_state sc_q;	/* pending I/O requests */
    246  1.37.8.2  nathanw 	int sc_active;		/* number of active I/O operations */
    247  1.37.8.2  nathanw 	u_char *sc_copybuf;	/* for secsize >=3 */
    248  1.37.8.2  nathanw 	u_char sc_part;		/* for secsize >=3 */
    249  1.37.8.2  nathanw #define	SEC_P10	0x02		/* first part */
    250  1.37.8.2  nathanw #define	SEC_P01	0x01		/* second part */
    251  1.37.8.2  nathanw #define	SEC_P11	0x03		/* both part */
    252  1.37.8.2  nathanw 
    253  1.37.8.2  nathanw #if NRND > 0
    254  1.37.8.2  nathanw 	rndsource_element_t	rnd_source;
    255  1.37.8.2  nathanw #endif
    256  1.37.8.2  nathanw };
    257  1.37.8.2  nathanw 
    258  1.37.8.2  nathanw /* floppy driver configuration */
    259  1.37.8.2  nathanw int fdprobe __P((struct device *, struct cfdata *, void *));
    260  1.37.8.2  nathanw void fdattach __P((struct device *, struct device *, void *));
    261  1.37.8.2  nathanw 
    262  1.37.8.6  nathanw CFATTACH_DECL(fd, sizeof(struct fd_softc),
    263  1.37.8.6  nathanw     fdprobe, fdattach, NULL, NULL);
    264  1.37.8.2  nathanw 
    265  1.37.8.2  nathanw extern struct cfdriver fd_cd;
    266  1.37.8.2  nathanw 
    267  1.37.8.5  nathanw dev_type_open(fdopen);
    268  1.37.8.5  nathanw dev_type_close(fdclose);
    269  1.37.8.5  nathanw dev_type_read(fdread);
    270  1.37.8.5  nathanw dev_type_write(fdwrite);
    271  1.37.8.5  nathanw dev_type_ioctl(fdioctl);
    272  1.37.8.5  nathanw dev_type_strategy(fdstrategy);
    273  1.37.8.5  nathanw 
    274  1.37.8.5  nathanw const struct bdevsw fd_bdevsw = {
    275  1.37.8.5  nathanw 	fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK
    276  1.37.8.5  nathanw };
    277  1.37.8.5  nathanw 
    278  1.37.8.5  nathanw const struct cdevsw fd_cdevsw = {
    279  1.37.8.5  nathanw 	fdopen, fdclose, fdread, fdwrite, fdioctl,
    280  1.37.8.5  nathanw 	nostop, notty, nopoll, nommap, D_DISK
    281  1.37.8.5  nathanw };
    282  1.37.8.5  nathanw 
    283  1.37.8.2  nathanw void fdstart __P((struct fd_softc *fd));
    284  1.37.8.2  nathanw 
    285  1.37.8.2  nathanw struct dkdriver fddkdriver = { fdstrategy };
    286  1.37.8.2  nathanw 
    287  1.37.8.2  nathanw void fd_set_motor __P((struct fdc_softc *fdc, int reset));
    288  1.37.8.2  nathanw void fd_motor_off __P((void *arg));
    289  1.37.8.2  nathanw void fd_motor_on __P((void *arg));
    290  1.37.8.2  nathanw int fdcresult __P((struct fdc_softc *fdc));
    291  1.37.8.2  nathanw int out_fdc __P((bus_space_tag_t, bus_space_handle_t, u_char x));
    292  1.37.8.2  nathanw void fdcstart __P((struct fdc_softc *fdc));
    293  1.37.8.2  nathanw void fdcstatus __P((struct device *dv, int n, char *s));
    294  1.37.8.2  nathanw void fdctimeout __P((void *arg));
    295  1.37.8.2  nathanw void fdcpseudointr __P((void *arg));
    296  1.37.8.2  nathanw void fdcretry __P((struct fdc_softc *fdc));
    297  1.37.8.2  nathanw void fdfinish __P((struct fd_softc *fd, struct buf *bp));
    298  1.37.8.2  nathanw __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
    299  1.37.8.2  nathanw static int fdcpoll __P((struct fdc_softc *));
    300  1.37.8.2  nathanw static int fdgetdisklabel __P((struct fd_softc *, dev_t));
    301  1.37.8.2  nathanw static void fd_do_eject __P((struct fdc_softc *, int));
    302  1.37.8.2  nathanw 
    303  1.37.8.2  nathanw void fd_mountroot_hook __P((struct device *));
    304  1.37.8.2  nathanw 
    305  1.37.8.2  nathanw /* dma transfer routines */
    306  1.37.8.2  nathanw __inline static void fdc_dmastart __P((struct fdc_softc*, int,
    307  1.37.8.2  nathanw 				       caddr_t, vsize_t));
    308  1.37.8.2  nathanw static int fdcdmaintr __P((void*));
    309  1.37.8.2  nathanw static int fdcdmaerrintr __P((void*));
    310  1.37.8.2  nathanw 
    311  1.37.8.2  nathanw __inline static void
    312  1.37.8.2  nathanw fdc_dmastart(fdc, read, addr, count)
    313  1.37.8.2  nathanw 	struct fdc_softc *fdc;
    314  1.37.8.2  nathanw 	int read;
    315  1.37.8.2  nathanw 	caddr_t addr;
    316  1.37.8.2  nathanw 	vsize_t count;
    317  1.37.8.2  nathanw {
    318  1.37.8.2  nathanw 	int error;
    319  1.37.8.2  nathanw 
    320  1.37.8.3  nathanw 	DPRINTF(("fdc_dmastart: (%s, addr = %p, count = %ld\n",
    321  1.37.8.2  nathanw 		 read ? "read" : "write", (caddr_t) addr, count));
    322  1.37.8.2  nathanw 
    323  1.37.8.2  nathanw 	error = bus_dmamap_load(fdc->sc_dmat, fdc->sc_dmamap, addr, count,
    324  1.37.8.2  nathanw 				0, BUS_DMA_NOWAIT);
    325  1.37.8.2  nathanw 	if (error) {
    326  1.37.8.2  nathanw 		panic ("fdc_dmastart: cannot load dmamap");
    327  1.37.8.2  nathanw 	}
    328  1.37.8.2  nathanw 
    329  1.37.8.2  nathanw 	bus_dmamap_sync(fdc->sc_dmat, fdc->sc_dmamap, 0, count,
    330  1.37.8.2  nathanw 			read?BUS_DMASYNC_PREREAD:BUS_DMASYNC_PREWRITE);
    331  1.37.8.2  nathanw 
    332  1.37.8.2  nathanw 	fdc->sc_xfer = dmac_prepare_xfer(fdc->sc_dmachan, fdc->sc_dmat,
    333  1.37.8.2  nathanw 					 fdc->sc_dmamap,
    334  1.37.8.2  nathanw 					 (read?
    335  1.37.8.2  nathanw 					  DMAC_OCR_DIR_DTM:DMAC_OCR_DIR_MTD),
    336  1.37.8.2  nathanw 					 (DMAC_SCR_MAC_COUNT_UP|
    337  1.37.8.2  nathanw 					  DMAC_SCR_DAC_NO_COUNT),
    338  1.37.8.2  nathanw 					 (u_int8_t*) (fdc->sc_addr +
    339  1.37.8.2  nathanw 						      fddata));	/* XXX */
    340  1.37.8.2  nathanw 
    341  1.37.8.2  nathanw 	dmac_start_xfer(fdc->sc_dmachan->ch_softc, fdc->sc_xfer);
    342  1.37.8.2  nathanw }
    343  1.37.8.2  nathanw 
    344  1.37.8.2  nathanw static int
    345  1.37.8.2  nathanw fdcdmaintr(arg)
    346  1.37.8.2  nathanw 	void *arg;
    347  1.37.8.2  nathanw {
    348  1.37.8.2  nathanw 	struct fdc_softc *fdc = arg;
    349  1.37.8.2  nathanw 
    350  1.37.8.2  nathanw 	bus_dmamap_unload(fdc->sc_dmat, fdc->sc_dmamap);
    351  1.37.8.2  nathanw 
    352  1.37.8.2  nathanw 	return 0;
    353  1.37.8.2  nathanw }
    354  1.37.8.2  nathanw 
    355  1.37.8.2  nathanw static int
    356  1.37.8.2  nathanw fdcdmaerrintr(dummy)
    357  1.37.8.2  nathanw 	void *dummy;
    358  1.37.8.2  nathanw {
    359  1.37.8.2  nathanw 	DPRINTF(("fdcdmaerrintr\n"));
    360  1.37.8.2  nathanw 
    361  1.37.8.2  nathanw 	return 0;
    362  1.37.8.2  nathanw }
    363  1.37.8.2  nathanw 
    364  1.37.8.2  nathanw /* ARGSUSED */
    365  1.37.8.2  nathanw int
    366  1.37.8.2  nathanw fdcprobe(parent, cf, aux)
    367  1.37.8.2  nathanw 	struct device *parent;
    368  1.37.8.2  nathanw 	struct cfdata *cf;
    369  1.37.8.2  nathanw 	void *aux;
    370  1.37.8.2  nathanw {
    371  1.37.8.2  nathanw 	struct intio_attach_args *ia = aux;
    372  1.37.8.2  nathanw 
    373  1.37.8.2  nathanw 	if (strcmp(ia->ia_name, "fdc") != 0)
    374  1.37.8.2  nathanw 		return 0;
    375  1.37.8.2  nathanw 
    376  1.37.8.2  nathanw 	if (ia->ia_addr == INTIOCF_ADDR_DEFAULT)
    377  1.37.8.2  nathanw 		ia->ia_addr = FDC_ADDR;
    378  1.37.8.2  nathanw 	if (ia->ia_intr == INTIOCF_INTR_DEFAULT)
    379  1.37.8.2  nathanw 		ia->ia_intr = FDC_INTR;
    380  1.37.8.2  nathanw 	if (ia->ia_dma == INTIOCF_DMA_DEFAULT)
    381  1.37.8.2  nathanw 		ia->ia_dma = FDC_DMA;
    382  1.37.8.2  nathanw 	if (ia->ia_dmaintr == INTIOCF_DMAINTR_DEFAULT)
    383  1.37.8.2  nathanw 		ia->ia_dmaintr = FDC_DMAINTR;
    384  1.37.8.2  nathanw 
    385  1.37.8.2  nathanw 	if ((ia->ia_intr & 0x03) != 0)
    386  1.37.8.2  nathanw 		return 0;
    387  1.37.8.2  nathanw 
    388  1.37.8.2  nathanw 	ia->ia_size = 0x2000;
    389  1.37.8.2  nathanw 	if (intio_map_allocate_region (parent, ia, INTIO_MAP_TESTONLY))
    390  1.37.8.2  nathanw 		return 0;
    391  1.37.8.2  nathanw 
    392  1.37.8.2  nathanw 	/* builtin device; always there */
    393  1.37.8.2  nathanw 	return 1;
    394  1.37.8.2  nathanw }
    395  1.37.8.2  nathanw 
    396  1.37.8.2  nathanw /*
    397  1.37.8.2  nathanw  * Arguments passed between fdcattach and fdprobe.
    398  1.37.8.2  nathanw  */
    399  1.37.8.2  nathanw struct fdc_attach_args {
    400  1.37.8.2  nathanw 	int fa_drive;
    401  1.37.8.2  nathanw 	struct fd_type *fa_deftype;
    402  1.37.8.2  nathanw };
    403  1.37.8.2  nathanw 
    404  1.37.8.2  nathanw /*
    405  1.37.8.2  nathanw  * Print the location of a disk drive (called just before attaching the
    406  1.37.8.2  nathanw  * the drive).  If `fdc' is not NULL, the drive was found but was not
    407  1.37.8.2  nathanw  * in the system config file; print the drive name as well.
    408  1.37.8.2  nathanw  * Return QUIET (config_find ignores this if the device was configured) to
    409  1.37.8.2  nathanw  * avoid printing `fdN not configured' messages.
    410  1.37.8.2  nathanw  */
    411  1.37.8.2  nathanw int
    412  1.37.8.2  nathanw fdprint(aux, fdc)
    413  1.37.8.2  nathanw 	void *aux;
    414  1.37.8.2  nathanw 	const char *fdc;
    415  1.37.8.2  nathanw {
    416  1.37.8.2  nathanw 	register struct fdc_attach_args *fa = aux;
    417  1.37.8.2  nathanw 
    418  1.37.8.2  nathanw 	if (!fdc)
    419  1.37.8.2  nathanw 		printf(" drive %d", fa->fa_drive);
    420  1.37.8.2  nathanw 	return QUIET;
    421  1.37.8.2  nathanw }
    422  1.37.8.2  nathanw 
    423  1.37.8.2  nathanw void
    424  1.37.8.2  nathanw fdcattach(parent, self, aux)
    425  1.37.8.2  nathanw 	struct device *parent, *self;
    426  1.37.8.2  nathanw 	void *aux;
    427  1.37.8.2  nathanw {
    428  1.37.8.2  nathanw 	struct fdc_softc *fdc = (void *)self;
    429  1.37.8.2  nathanw 	bus_space_tag_t iot;
    430  1.37.8.2  nathanw 	bus_space_handle_t ioh;
    431  1.37.8.2  nathanw 	struct intio_attach_args *ia = aux;
    432  1.37.8.2  nathanw 	struct fdc_attach_args fa;
    433  1.37.8.2  nathanw 
    434  1.37.8.2  nathanw 	iot = ia->ia_bst;
    435  1.37.8.2  nathanw 
    436  1.37.8.2  nathanw 	printf("\n");
    437  1.37.8.2  nathanw 
    438  1.37.8.2  nathanw 	callout_init(&fdc->sc_timo_ch);
    439  1.37.8.2  nathanw 	callout_init(&fdc->sc_intr_ch);
    440  1.37.8.2  nathanw 
    441  1.37.8.2  nathanw 	/* Re-map the I/O space. */
    442  1.37.8.2  nathanw 	bus_space_map(iot, ia->ia_addr, 0x2000, BUS_SPACE_MAP_SHIFTED, &ioh);
    443  1.37.8.2  nathanw 
    444  1.37.8.2  nathanw 	fdc->sc_iot = iot;
    445  1.37.8.2  nathanw 	fdc->sc_ioh = ioh;
    446  1.37.8.2  nathanw 	fdc->sc_addr = (void*) ia->ia_addr;
    447  1.37.8.2  nathanw 
    448  1.37.8.2  nathanw 	fdc->sc_dmat = ia->ia_dmat;
    449  1.37.8.2  nathanw 	fdc->sc_state = DEVIDLE;
    450  1.37.8.2  nathanw 	TAILQ_INIT(&fdc->sc_drives);
    451  1.37.8.2  nathanw 
    452  1.37.8.2  nathanw 	/* Initialize DMAC channel */
    453  1.37.8.2  nathanw 	fdc->sc_dmachan = dmac_alloc_channel(parent, ia->ia_dma, "fdc",
    454  1.37.8.2  nathanw 					     ia->ia_dmaintr, fdcdmaintr, fdc,
    455  1.37.8.2  nathanw 					     ia->ia_dmaintr+1, fdcdmaerrintr,
    456  1.37.8.2  nathanw 					     fdc);
    457  1.37.8.2  nathanw 	if (bus_dmamap_create(fdc->sc_dmat, FDC_MAXIOSIZE, 1, DMAC_MAXSEGSZ,
    458  1.37.8.2  nathanw 			      0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
    459  1.37.8.2  nathanw 			      &fdc->sc_dmamap)) {
    460  1.37.8.2  nathanw 		printf("%s: can't set up intio DMA map\n",
    461  1.37.8.2  nathanw 		    fdc->sc_dev.dv_xname);
    462  1.37.8.2  nathanw 		return;
    463  1.37.8.2  nathanw 	}
    464  1.37.8.2  nathanw 
    465  1.37.8.2  nathanw 	if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc))
    466  1.37.8.2  nathanw 		panic ("Could not establish interrupt (duplicated vector?).");
    467  1.37.8.2  nathanw 	intio_set_ivec(ia->ia_intr);
    468  1.37.8.2  nathanw 
    469  1.37.8.2  nathanw 	/* reset */
    470  1.37.8.2  nathanw 	intio_disable_intr(SICILIAN_INTR_FDD);
    471  1.37.8.2  nathanw 	intio_enable_intr(SICILIAN_INTR_FDC);
    472  1.37.8.2  nathanw 	fdcresult(fdc);
    473  1.37.8.2  nathanw 	fdcreset(fdc);
    474  1.37.8.2  nathanw 
    475  1.37.8.2  nathanw 	printf("%s: uPD72065 FDC\n", fdc->sc_dev.dv_xname);
    476  1.37.8.2  nathanw 	out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
    477  1.37.8.2  nathanw 	out_fdc(iot, ioh, 0xd0);
    478  1.37.8.2  nathanw 	out_fdc(iot, ioh, 0x10);
    479  1.37.8.2  nathanw 
    480  1.37.8.2  nathanw 	/* physical limit: four drives per controller. */
    481  1.37.8.2  nathanw 	for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
    482  1.37.8.2  nathanw 		(void)config_found(self, (void *)&fa, fdprint);
    483  1.37.8.2  nathanw 	}
    484  1.37.8.2  nathanw 
    485  1.37.8.2  nathanw 	intio_enable_intr(SICILIAN_INTR_FDC);
    486  1.37.8.2  nathanw }
    487  1.37.8.2  nathanw 
    488  1.37.8.2  nathanw void
    489  1.37.8.2  nathanw fdcreset(fdc)
    490  1.37.8.2  nathanw 	struct fdc_softc *fdc;
    491  1.37.8.2  nathanw {
    492  1.37.8.2  nathanw 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdsts, NE7CMD_RESET);
    493  1.37.8.2  nathanw }
    494  1.37.8.2  nathanw 
    495  1.37.8.2  nathanw static int
    496  1.37.8.2  nathanw fdcpoll(fdc)
    497  1.37.8.2  nathanw 	struct fdc_softc *fdc;
    498  1.37.8.2  nathanw {
    499  1.37.8.2  nathanw 	int i = 25000, n;
    500  1.37.8.2  nathanw 	while (--i > 0) {
    501  1.37.8.2  nathanw 		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
    502  1.37.8.2  nathanw 			out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
    503  1.37.8.2  nathanw 			n = fdcresult(fdc);
    504  1.37.8.2  nathanw 			break;
    505  1.37.8.2  nathanw 		}
    506  1.37.8.2  nathanw 		DELAY(100);
    507  1.37.8.2  nathanw 	}
    508  1.37.8.2  nathanw 	return i;
    509  1.37.8.2  nathanw }
    510  1.37.8.2  nathanw 
    511  1.37.8.2  nathanw int
    512  1.37.8.2  nathanw fdprobe(parent, cf, aux)
    513  1.37.8.2  nathanw 	struct device *parent;
    514  1.37.8.2  nathanw 	struct cfdata *cf;
    515  1.37.8.2  nathanw 	void *aux;
    516  1.37.8.2  nathanw {
    517  1.37.8.2  nathanw 	struct fdc_softc *fdc = (void *)parent;
    518  1.37.8.2  nathanw 	struct fd_type *type;
    519  1.37.8.2  nathanw 	struct fdc_attach_args *fa = aux;
    520  1.37.8.2  nathanw 	int drive = fa->fa_drive;
    521  1.37.8.2  nathanw 	bus_space_tag_t iot = fdc->sc_iot;
    522  1.37.8.2  nathanw 	bus_space_handle_t ioh = fdc->sc_ioh;
    523  1.37.8.2  nathanw 	int n;
    524  1.37.8.2  nathanw 	int found = 0;
    525  1.37.8.2  nathanw 	int i;
    526  1.37.8.2  nathanw 
    527  1.37.8.2  nathanw 	if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
    528  1.37.8.2  nathanw 	    cf->cf_loc[FDCCF_UNIT] != drive)
    529  1.37.8.2  nathanw 		return 0;
    530  1.37.8.2  nathanw 
    531  1.37.8.2  nathanw 	type = &fd_types[0];	/* XXX 1.2MB */
    532  1.37.8.2  nathanw 
    533  1.37.8.2  nathanw 	intio_disable_intr(SICILIAN_INTR_FDC);
    534  1.37.8.2  nathanw 
    535  1.37.8.2  nathanw 	/* select drive and turn on motor */
    536  1.37.8.2  nathanw 	bus_space_write_1(iot, ioh, fdctl, 0x80 | (type->rate << 4)| drive);
    537  1.37.8.2  nathanw 	fdc_force_ready(FDCRDY);
    538  1.37.8.2  nathanw 	fdcpoll(fdc);
    539  1.37.8.2  nathanw 
    540  1.37.8.2  nathanw retry:
    541  1.37.8.2  nathanw 	out_fdc(iot, ioh, NE7CMD_RECAL);
    542  1.37.8.2  nathanw 	out_fdc(iot, ioh, drive);
    543  1.37.8.2  nathanw 
    544  1.37.8.2  nathanw 	i = 25000;
    545  1.37.8.2  nathanw 	while (--i > 0) {
    546  1.37.8.2  nathanw 		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
    547  1.37.8.2  nathanw 			out_fdc(iot, ioh, NE7CMD_SENSEI);
    548  1.37.8.2  nathanw 			n = fdcresult(fdc);
    549  1.37.8.2  nathanw 			break;
    550  1.37.8.2  nathanw 		}
    551  1.37.8.2  nathanw 		DELAY(100);
    552  1.37.8.2  nathanw 	}
    553  1.37.8.2  nathanw 
    554  1.37.8.2  nathanw #ifdef FDDEBUG
    555  1.37.8.2  nathanw 	{
    556  1.37.8.2  nathanw 		int i;
    557  1.37.8.2  nathanw 		DPRINTF(("fdprobe: status"));
    558  1.37.8.2  nathanw 		for (i = 0; i < n; i++)
    559  1.37.8.2  nathanw 			DPRINTF((" %x", fdc->sc_status[i]));
    560  1.37.8.2  nathanw 		DPRINTF(("\n"));
    561  1.37.8.2  nathanw 	}
    562  1.37.8.2  nathanw #endif
    563  1.37.8.2  nathanw 
    564  1.37.8.2  nathanw 	if (n == 2) {
    565  1.37.8.2  nathanw 		if ((fdc->sc_status[0] & 0xf0) == 0x20) {
    566  1.37.8.2  nathanw 			found = 1;
    567  1.37.8.2  nathanw 		} else if ((fdc->sc_status[0] & 0xf0) == 0xc0) {
    568  1.37.8.2  nathanw 			goto retry;
    569  1.37.8.2  nathanw 		}
    570  1.37.8.2  nathanw 	}
    571  1.37.8.2  nathanw 
    572  1.37.8.2  nathanw 	/* turn off motor */
    573  1.37.8.2  nathanw 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh,
    574  1.37.8.2  nathanw 			  fdctl, (type->rate << 4)| drive);
    575  1.37.8.2  nathanw 	fdc_force_ready(FDCSTBY);
    576  1.37.8.2  nathanw 	if (!found) {
    577  1.37.8.2  nathanw 		intio_enable_intr(SICILIAN_INTR_FDC);
    578  1.37.8.2  nathanw 		return 0;
    579  1.37.8.2  nathanw 	}
    580  1.37.8.2  nathanw 
    581  1.37.8.2  nathanw 	return 1;
    582  1.37.8.2  nathanw }
    583  1.37.8.2  nathanw 
    584  1.37.8.2  nathanw /*
    585  1.37.8.2  nathanw  * Controller is working, and drive responded.  Attach it.
    586  1.37.8.2  nathanw  */
    587  1.37.8.2  nathanw void
    588  1.37.8.2  nathanw fdattach(parent, self, aux)
    589  1.37.8.2  nathanw 	struct device *parent, *self;
    590  1.37.8.2  nathanw 	void *aux;
    591  1.37.8.2  nathanw {
    592  1.37.8.2  nathanw 	struct fdc_softc *fdc = (void *)parent;
    593  1.37.8.2  nathanw 	struct fd_softc *fd = (void *)self;
    594  1.37.8.2  nathanw 	struct fdc_attach_args *fa = aux;
    595  1.37.8.2  nathanw 	struct fd_type *type = &fd_types[0];	/* XXX 1.2MB */
    596  1.37.8.2  nathanw 	int drive = fa->fa_drive;
    597  1.37.8.2  nathanw 
    598  1.37.8.2  nathanw 	callout_init(&fd->sc_motoron_ch);
    599  1.37.8.2  nathanw 	callout_init(&fd->sc_motoroff_ch);
    600  1.37.8.2  nathanw 
    601  1.37.8.2  nathanw 	fd->sc_flags = 0;
    602  1.37.8.2  nathanw 
    603  1.37.8.2  nathanw 	if (type)
    604  1.37.8.2  nathanw 		printf(": %s, %d cyl, %d head, %d sec\n", type->name,
    605  1.37.8.2  nathanw 		       type->cyls, type->heads, type->sectrac);
    606  1.37.8.2  nathanw 	else
    607  1.37.8.2  nathanw 		printf(": density unknown\n");
    608  1.37.8.2  nathanw 
    609  1.37.8.4  nathanw 	bufq_alloc(&fd->sc_q, BUFQ_DISKSORT|BUFQ_SORT_CYLINDER);
    610  1.37.8.2  nathanw 	fd->sc_cylin = -1;
    611  1.37.8.2  nathanw 	fd->sc_drive = drive;
    612  1.37.8.2  nathanw 	fd->sc_deftype = type;
    613  1.37.8.2  nathanw 	fdc->sc_fd[drive] = fd;
    614  1.37.8.2  nathanw 
    615  1.37.8.2  nathanw 	fd->sc_copybuf = (u_char *)malloc(NBPG, M_DEVBUF, M_WAITOK);
    616  1.37.8.2  nathanw 	if (fd->sc_copybuf == 0)
    617  1.37.8.2  nathanw 		printf("fdprobe: WARNING!! malloc() failed.\n");
    618  1.37.8.2  nathanw 	fd->sc_flags |= FD_ALIVE;
    619  1.37.8.2  nathanw 
    620  1.37.8.2  nathanw 	/*
    621  1.37.8.2  nathanw 	 * Initialize and attach the disk structure.
    622  1.37.8.2  nathanw 	 */
    623  1.37.8.2  nathanw 	fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
    624  1.37.8.2  nathanw 	fd->sc_dk.dk_driver = &fddkdriver;
    625  1.37.8.2  nathanw 	disk_attach(&fd->sc_dk);
    626  1.37.8.2  nathanw 
    627  1.37.8.2  nathanw 	/*
    628  1.37.8.2  nathanw 	 * Establish a mountroot_hook anyway in case we booted
    629  1.37.8.2  nathanw 	 * with RB_ASKNAME and get selected as the boot device.
    630  1.37.8.2  nathanw 	 */
    631  1.37.8.2  nathanw 	mountroothook_establish(fd_mountroot_hook, &fd->sc_dev);
    632  1.37.8.2  nathanw 
    633  1.37.8.2  nathanw #if NRND > 0
    634  1.37.8.2  nathanw 	rnd_attach_source(&fd->rnd_source, fd->sc_dev.dv_xname,
    635  1.37.8.2  nathanw 			  RND_TYPE_DISK, 0);
    636  1.37.8.2  nathanw #endif
    637  1.37.8.2  nathanw }
    638  1.37.8.2  nathanw 
    639  1.37.8.2  nathanw __inline struct fd_type *
    640  1.37.8.2  nathanw fd_dev_to_type(fd, dev)
    641  1.37.8.2  nathanw 	struct fd_softc *fd;
    642  1.37.8.2  nathanw 	dev_t dev;
    643  1.37.8.2  nathanw {
    644  1.37.8.2  nathanw 	int type = FDTYPE(dev);
    645  1.37.8.2  nathanw 
    646  1.37.8.2  nathanw 	if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
    647  1.37.8.2  nathanw 		return NULL;
    648  1.37.8.2  nathanw 	return &fd_types[type];
    649  1.37.8.2  nathanw }
    650  1.37.8.2  nathanw 
    651  1.37.8.2  nathanw void
    652  1.37.8.2  nathanw fdstrategy(bp)
    653  1.37.8.2  nathanw 	register struct buf *bp;	/* IO operation to perform */
    654  1.37.8.2  nathanw {
    655  1.37.8.2  nathanw 	struct fd_softc *fd;
    656  1.37.8.2  nathanw 	int unit = FDUNIT(bp->b_dev);
    657  1.37.8.2  nathanw 	int sz;
    658  1.37.8.2  nathanw  	int s;
    659  1.37.8.2  nathanw 
    660  1.37.8.2  nathanw 	if (unit >= fd_cd.cd_ndevs ||
    661  1.37.8.2  nathanw 	    (fd = fd_cd.cd_devs[unit]) == 0 ||
    662  1.37.8.2  nathanw 	    bp->b_blkno < 0 ||
    663  1.37.8.2  nathanw 	    (bp->b_bcount % FDC_BSIZE) != 0) {
    664  1.37.8.3  nathanw 		DPRINTF(("fdstrategy: unit=%d, blkno=%d, bcount=%ld\n", unit,
    665  1.37.8.2  nathanw 			 bp->b_blkno, bp->b_bcount));
    666  1.37.8.2  nathanw 		bp->b_error = EINVAL;
    667  1.37.8.2  nathanw 		goto bad;
    668  1.37.8.2  nathanw 	}
    669  1.37.8.2  nathanw 
    670  1.37.8.2  nathanw 	/* If it's a null transfer, return immediately. */
    671  1.37.8.2  nathanw 	if (bp->b_bcount == 0)
    672  1.37.8.2  nathanw 		goto done;
    673  1.37.8.2  nathanw 
    674  1.37.8.2  nathanw 	sz = howmany(bp->b_bcount, FDC_BSIZE);
    675  1.37.8.2  nathanw 
    676  1.37.8.6  nathanw 	if (bp->b_blkno + sz >
    677  1.37.8.6  nathanw 	    (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
    678  1.37.8.6  nathanw 		sz = (fd->sc_type->size << (fd->sc_type->secsize - 2))
    679  1.37.8.6  nathanw 		     - bp->b_blkno;
    680  1.37.8.2  nathanw 		if (sz == 0) {
    681  1.37.8.2  nathanw 			/* If exactly at end of disk, return EOF. */
    682  1.37.8.2  nathanw 			bp->b_resid = bp->b_bcount;
    683  1.37.8.2  nathanw 			goto done;
    684  1.37.8.2  nathanw 		}
    685  1.37.8.2  nathanw 		if (sz < 0) {
    686  1.37.8.2  nathanw 			/* If past end of disk, return EINVAL. */
    687  1.37.8.2  nathanw 			bp->b_error = EINVAL;
    688  1.37.8.2  nathanw 			goto bad;
    689  1.37.8.2  nathanw 		}
    690  1.37.8.2  nathanw 		/* Otherwise, truncate request. */
    691  1.37.8.2  nathanw 		bp->b_bcount = sz << DEV_BSHIFT;
    692  1.37.8.2  nathanw 	}
    693  1.37.8.2  nathanw 
    694  1.37.8.2  nathanw 	bp->b_rawblkno = bp->b_blkno;
    695  1.37.8.2  nathanw  	bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)
    696  1.37.8.2  nathanw 		/ (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2)));
    697  1.37.8.2  nathanw 
    698  1.37.8.2  nathanw 	DPRINTF(("fdstrategy: %s b_blkno %d b_bcount %ld cylin %ld\n",
    699  1.37.8.2  nathanw 		 bp->b_flags & B_READ ? "read" : "write",
    700  1.37.8.2  nathanw 		 bp->b_blkno, bp->b_bcount, bp->b_cylinder));
    701  1.37.8.2  nathanw 	/* Queue transfer on drive, activate drive and controller if idle. */
    702  1.37.8.2  nathanw 	s = splbio();
    703  1.37.8.4  nathanw 	BUFQ_PUT(&fd->sc_q, bp);
    704  1.37.8.2  nathanw 	callout_stop(&fd->sc_motoroff_ch);		/* a good idea */
    705  1.37.8.2  nathanw 	if (fd->sc_active == 0)
    706  1.37.8.2  nathanw 		fdstart(fd);
    707  1.37.8.2  nathanw #ifdef DIAGNOSTIC
    708  1.37.8.2  nathanw 	else {
    709  1.37.8.2  nathanw 		struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    710  1.37.8.2  nathanw 		if (fdc->sc_state == DEVIDLE) {
    711  1.37.8.2  nathanw 			printf("fdstrategy: controller inactive\n");
    712  1.37.8.2  nathanw 			fdcstart(fdc);
    713  1.37.8.2  nathanw 		}
    714  1.37.8.2  nathanw 	}
    715  1.37.8.2  nathanw #endif
    716  1.37.8.2  nathanw 	splx(s);
    717  1.37.8.2  nathanw 	return;
    718  1.37.8.2  nathanw 
    719  1.37.8.2  nathanw bad:
    720  1.37.8.2  nathanw 	bp->b_flags |= B_ERROR;
    721  1.37.8.2  nathanw done:
    722  1.37.8.2  nathanw 	/* Toss transfer; we're done early. */
    723  1.37.8.2  nathanw 	biodone(bp);
    724  1.37.8.2  nathanw }
    725  1.37.8.2  nathanw 
    726  1.37.8.2  nathanw void
    727  1.37.8.2  nathanw fdstart(fd)
    728  1.37.8.2  nathanw 	struct fd_softc *fd;
    729  1.37.8.2  nathanw {
    730  1.37.8.2  nathanw 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    731  1.37.8.2  nathanw 	int active = fdc->sc_drives.tqh_first != 0;
    732  1.37.8.2  nathanw 
    733  1.37.8.2  nathanw 	/* Link into controller queue. */
    734  1.37.8.2  nathanw 	fd->sc_active = 1;
    735  1.37.8.2  nathanw 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    736  1.37.8.2  nathanw 
    737  1.37.8.2  nathanw 	/* If controller not already active, start it. */
    738  1.37.8.2  nathanw 	if (!active)
    739  1.37.8.2  nathanw 		fdcstart(fdc);
    740  1.37.8.2  nathanw }
    741  1.37.8.2  nathanw 
    742  1.37.8.2  nathanw void
    743  1.37.8.2  nathanw fdfinish(fd, bp)
    744  1.37.8.2  nathanw 	struct fd_softc *fd;
    745  1.37.8.2  nathanw 	struct buf *bp;
    746  1.37.8.2  nathanw {
    747  1.37.8.2  nathanw 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    748  1.37.8.2  nathanw 
    749  1.37.8.2  nathanw 	/*
    750  1.37.8.2  nathanw 	 * Move this drive to the end of the queue to give others a `fair'
    751  1.37.8.2  nathanw 	 * chance.  We only force a switch if N operations are completed while
    752  1.37.8.2  nathanw 	 * another drive is waiting to be serviced, since there is a long motor
    753  1.37.8.2  nathanw 	 * startup delay whenever we switch.
    754  1.37.8.2  nathanw 	 */
    755  1.37.8.4  nathanw 	(void)BUFQ_GET(&fd->sc_q);
    756  1.37.8.2  nathanw 	if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
    757  1.37.8.2  nathanw 		fd->sc_ops = 0;
    758  1.37.8.2  nathanw 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
    759  1.37.8.4  nathanw 		if (BUFQ_PEEK(&fd->sc_q) != NULL) {
    760  1.37.8.2  nathanw 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    761  1.37.8.2  nathanw 		} else
    762  1.37.8.2  nathanw 			fd->sc_active = 0;
    763  1.37.8.2  nathanw 	}
    764  1.37.8.2  nathanw 	bp->b_resid = fd->sc_bcount;
    765  1.37.8.2  nathanw 	fd->sc_skip = 0;
    766  1.37.8.2  nathanw 
    767  1.37.8.2  nathanw #if NRND > 0
    768  1.37.8.2  nathanw 	rnd_add_uint32(&fd->rnd_source, bp->b_blkno);
    769  1.37.8.2  nathanw #endif
    770  1.37.8.2  nathanw 
    771  1.37.8.2  nathanw 	biodone(bp);
    772  1.37.8.2  nathanw 	/* turn off motor 5s from now */
    773  1.37.8.2  nathanw 	callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
    774  1.37.8.2  nathanw 	fdc->sc_state = DEVIDLE;
    775  1.37.8.2  nathanw }
    776  1.37.8.2  nathanw 
    777  1.37.8.2  nathanw int
    778  1.37.8.2  nathanw fdread(dev, uio, flags)
    779  1.37.8.2  nathanw 	dev_t dev;
    780  1.37.8.2  nathanw 	struct uio *uio;
    781  1.37.8.2  nathanw 	int flags;
    782  1.37.8.2  nathanw {
    783  1.37.8.2  nathanw 
    784  1.37.8.2  nathanw 	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
    785  1.37.8.2  nathanw }
    786  1.37.8.2  nathanw 
    787  1.37.8.2  nathanw int
    788  1.37.8.2  nathanw fdwrite(dev, uio, flags)
    789  1.37.8.2  nathanw 	dev_t dev;
    790  1.37.8.2  nathanw 	struct uio *uio;
    791  1.37.8.2  nathanw 	int flags;
    792  1.37.8.2  nathanw {
    793  1.37.8.2  nathanw 
    794  1.37.8.2  nathanw 	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
    795  1.37.8.2  nathanw }
    796  1.37.8.2  nathanw 
    797  1.37.8.2  nathanw void
    798  1.37.8.2  nathanw fd_set_motor(fdc, reset)
    799  1.37.8.2  nathanw 	struct fdc_softc *fdc;
    800  1.37.8.2  nathanw 	int reset;
    801  1.37.8.2  nathanw {
    802  1.37.8.2  nathanw 	struct fd_softc *fd;
    803  1.37.8.2  nathanw 	int n;
    804  1.37.8.2  nathanw 
    805  1.37.8.2  nathanw 	DPRINTF(("fd_set_motor:\n"));
    806  1.37.8.2  nathanw 	for (n = 0; n < 4; n++)
    807  1.37.8.2  nathanw 		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) {
    808  1.37.8.2  nathanw 			bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl,
    809  1.37.8.2  nathanw 					  0x80 | (fd->sc_type->rate << 4)| n);
    810  1.37.8.2  nathanw 		}
    811  1.37.8.2  nathanw }
    812  1.37.8.2  nathanw 
    813  1.37.8.2  nathanw void
    814  1.37.8.2  nathanw fd_motor_off(arg)
    815  1.37.8.2  nathanw 	void *arg;
    816  1.37.8.2  nathanw {
    817  1.37.8.2  nathanw 	struct fd_softc *fd = arg;
    818  1.37.8.2  nathanw 	struct fdc_softc *fdc = (struct fdc_softc*) fd->sc_dev.dv_parent;
    819  1.37.8.2  nathanw 	int s;
    820  1.37.8.2  nathanw 
    821  1.37.8.2  nathanw 	DPRINTF(("fd_motor_off:\n"));
    822  1.37.8.2  nathanw 
    823  1.37.8.2  nathanw 	s = splbio();
    824  1.37.8.2  nathanw 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
    825  1.37.8.2  nathanw 	bus_space_write_1 (fdc->sc_iot, fdc->sc_ioh, fdctl,
    826  1.37.8.2  nathanw 			   (fd->sc_type->rate << 4) | fd->sc_drive);
    827  1.37.8.2  nathanw #if 0
    828  1.37.8.2  nathanw 	fd_set_motor(fdc, 0); /* XXX */
    829  1.37.8.2  nathanw #endif
    830  1.37.8.2  nathanw 	splx(s);
    831  1.37.8.2  nathanw }
    832  1.37.8.2  nathanw 
    833  1.37.8.2  nathanw void
    834  1.37.8.2  nathanw fd_motor_on(arg)
    835  1.37.8.2  nathanw 	void *arg;
    836  1.37.8.2  nathanw {
    837  1.37.8.2  nathanw 	struct fd_softc *fd = arg;
    838  1.37.8.2  nathanw 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    839  1.37.8.2  nathanw 	int s;
    840  1.37.8.2  nathanw 
    841  1.37.8.2  nathanw 	DPRINTF(("fd_motor_on:\n"));
    842  1.37.8.2  nathanw 
    843  1.37.8.2  nathanw 	s = splbio();
    844  1.37.8.2  nathanw 	fd->sc_flags &= ~FD_MOTOR_WAIT;
    845  1.37.8.2  nathanw 	if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
    846  1.37.8.2  nathanw 		(void) fdcintr(fdc);
    847  1.37.8.2  nathanw 	splx(s);
    848  1.37.8.2  nathanw }
    849  1.37.8.2  nathanw 
    850  1.37.8.2  nathanw int
    851  1.37.8.2  nathanw fdcresult(fdc)
    852  1.37.8.2  nathanw 	struct fdc_softc *fdc;
    853  1.37.8.2  nathanw {
    854  1.37.8.2  nathanw 	bus_space_tag_t iot = fdc->sc_iot;
    855  1.37.8.2  nathanw 	bus_space_handle_t ioh = fdc->sc_ioh;
    856  1.37.8.2  nathanw 	u_char i;
    857  1.37.8.2  nathanw 	int j = 100000,
    858  1.37.8.2  nathanw 	    n = 0;
    859  1.37.8.2  nathanw 
    860  1.37.8.2  nathanw 	for (; j; j--) {
    861  1.37.8.2  nathanw 		i = bus_space_read_1(iot, ioh, fdsts) &
    862  1.37.8.2  nathanw 		  (NE7_DIO | NE7_RQM | NE7_CB);
    863  1.37.8.2  nathanw 
    864  1.37.8.2  nathanw 		if (i == NE7_RQM)
    865  1.37.8.2  nathanw 			return n;
    866  1.37.8.2  nathanw 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
    867  1.37.8.2  nathanw 			if (n >= sizeof(fdc->sc_status)) {
    868  1.37.8.2  nathanw 				log(LOG_ERR, "fdcresult: overrun\n");
    869  1.37.8.2  nathanw 				return -1;
    870  1.37.8.2  nathanw 			}
    871  1.37.8.2  nathanw 			fdc->sc_status[n++] =
    872  1.37.8.2  nathanw 			  bus_space_read_1(iot, ioh, fddata);
    873  1.37.8.2  nathanw 		}
    874  1.37.8.2  nathanw 		delay(10);
    875  1.37.8.2  nathanw 	}
    876  1.37.8.2  nathanw 	log(LOG_ERR, "fdcresult: timeout\n");
    877  1.37.8.2  nathanw 	return -1;
    878  1.37.8.2  nathanw }
    879  1.37.8.2  nathanw 
    880  1.37.8.2  nathanw int
    881  1.37.8.2  nathanw out_fdc(iot, ioh, x)
    882  1.37.8.2  nathanw 	bus_space_tag_t iot;
    883  1.37.8.2  nathanw 	bus_space_handle_t ioh;
    884  1.37.8.2  nathanw 	u_char x;
    885  1.37.8.2  nathanw {
    886  1.37.8.2  nathanw 	int i = 100000;
    887  1.37.8.2  nathanw 
    888  1.37.8.2  nathanw 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
    889  1.37.8.2  nathanw 	if (i <= 0)
    890  1.37.8.2  nathanw 		return -1;
    891  1.37.8.2  nathanw 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
    892  1.37.8.2  nathanw 	if (i <= 0)
    893  1.37.8.2  nathanw 		return -1;
    894  1.37.8.2  nathanw 	bus_space_write_1(iot, ioh, fddata, x);
    895  1.37.8.2  nathanw 	return 0;
    896  1.37.8.2  nathanw }
    897  1.37.8.2  nathanw 
    898  1.37.8.2  nathanw int
    899  1.37.8.2  nathanw fdopen(dev, flags, mode, p)
    900  1.37.8.2  nathanw 	dev_t dev;
    901  1.37.8.2  nathanw 	int flags, mode;
    902  1.37.8.2  nathanw 	struct proc *p;
    903  1.37.8.2  nathanw {
    904  1.37.8.2  nathanw  	int unit;
    905  1.37.8.2  nathanw 	struct fd_softc *fd;
    906  1.37.8.2  nathanw 	struct fd_type *type;
    907  1.37.8.2  nathanw 	struct fdc_softc *fdc;
    908  1.37.8.2  nathanw 
    909  1.37.8.2  nathanw 	unit = FDUNIT(dev);
    910  1.37.8.2  nathanw 	if (unit >= fd_cd.cd_ndevs)
    911  1.37.8.2  nathanw 		return ENXIO;
    912  1.37.8.2  nathanw 	fd = fd_cd.cd_devs[unit];
    913  1.37.8.2  nathanw 	if (fd == 0)
    914  1.37.8.2  nathanw 		return ENXIO;
    915  1.37.8.2  nathanw 	type = fd_dev_to_type(fd, dev);
    916  1.37.8.2  nathanw 	if (type == NULL)
    917  1.37.8.2  nathanw 		return ENXIO;
    918  1.37.8.2  nathanw 
    919  1.37.8.2  nathanw 	if ((fd->sc_flags & FD_OPEN) != 0 &&
    920  1.37.8.2  nathanw 	    fd->sc_type != type)
    921  1.37.8.2  nathanw 		return EBUSY;
    922  1.37.8.2  nathanw 
    923  1.37.8.2  nathanw 	fdc = (void *)fd->sc_dev.dv_parent;
    924  1.37.8.2  nathanw 	if ((fd->sc_flags & FD_OPEN) == 0) {
    925  1.37.8.2  nathanw 		/* Lock eject button */
    926  1.37.8.2  nathanw 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
    927  1.37.8.2  nathanw 				  0x40 | ( 1 << unit));
    928  1.37.8.2  nathanw 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x40);
    929  1.37.8.2  nathanw 	}
    930  1.37.8.2  nathanw 
    931  1.37.8.2  nathanw 	fd->sc_type = type;
    932  1.37.8.2  nathanw 	fd->sc_cylin = -1;
    933  1.37.8.2  nathanw 
    934  1.37.8.2  nathanw 	switch (mode) {
    935  1.37.8.2  nathanw 	case S_IFCHR:
    936  1.37.8.2  nathanw 		fd->sc_flags |= FD_COPEN;
    937  1.37.8.2  nathanw 		break;
    938  1.37.8.2  nathanw 	case S_IFBLK:
    939  1.37.8.2  nathanw 		fd->sc_flags |= FD_BOPEN;
    940  1.37.8.2  nathanw 		break;
    941  1.37.8.2  nathanw 	}
    942  1.37.8.2  nathanw 
    943  1.37.8.2  nathanw 	fdgetdisklabel(fd, dev);
    944  1.37.8.2  nathanw 
    945  1.37.8.2  nathanw 	return 0;
    946  1.37.8.2  nathanw }
    947  1.37.8.2  nathanw 
    948  1.37.8.2  nathanw int
    949  1.37.8.2  nathanw fdclose(dev, flags, mode, p)
    950  1.37.8.2  nathanw 	dev_t dev;
    951  1.37.8.2  nathanw 	int flags, mode;
    952  1.37.8.2  nathanw 	struct proc *p;
    953  1.37.8.2  nathanw {
    954  1.37.8.2  nathanw  	int unit = FDUNIT(dev);
    955  1.37.8.2  nathanw 	struct fd_softc *fd = fd_cd.cd_devs[unit];
    956  1.37.8.2  nathanw 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    957  1.37.8.2  nathanw 
    958  1.37.8.2  nathanw 	DPRINTF(("fdclose %d\n", unit));
    959  1.37.8.2  nathanw 
    960  1.37.8.2  nathanw 	switch (mode) {
    961  1.37.8.2  nathanw 	case S_IFCHR:
    962  1.37.8.2  nathanw 		fd->sc_flags &= ~FD_COPEN;
    963  1.37.8.2  nathanw 		break;
    964  1.37.8.2  nathanw 	case S_IFBLK:
    965  1.37.8.2  nathanw 		fd->sc_flags &= ~FD_BOPEN;
    966  1.37.8.2  nathanw 		break;
    967  1.37.8.2  nathanw 	}
    968  1.37.8.2  nathanw 
    969  1.37.8.2  nathanw 	if ((fd->sc_flags & FD_OPEN) == 0) {
    970  1.37.8.2  nathanw 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
    971  1.37.8.2  nathanw 				  ( 1 << unit));
    972  1.37.8.2  nathanw 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0);
    973  1.37.8.2  nathanw 	}
    974  1.37.8.2  nathanw 	return 0;
    975  1.37.8.2  nathanw }
    976  1.37.8.2  nathanw 
    977  1.37.8.2  nathanw void
    978  1.37.8.2  nathanw fdcstart(fdc)
    979  1.37.8.2  nathanw 	struct fdc_softc *fdc;
    980  1.37.8.2  nathanw {
    981  1.37.8.2  nathanw 
    982  1.37.8.2  nathanw #ifdef DIAGNOSTIC
    983  1.37.8.2  nathanw 	/* only got here if controller's drive queue was inactive; should
    984  1.37.8.2  nathanw 	   be in idle state */
    985  1.37.8.2  nathanw 	if (fdc->sc_state != DEVIDLE) {
    986  1.37.8.2  nathanw 		printf("fdcstart: not idle\n");
    987  1.37.8.2  nathanw 		return;
    988  1.37.8.2  nathanw 	}
    989  1.37.8.2  nathanw #endif
    990  1.37.8.2  nathanw 	(void) fdcintr(fdc);
    991  1.37.8.2  nathanw }
    992  1.37.8.2  nathanw 
    993  1.37.8.2  nathanw void
    994  1.37.8.2  nathanw fdcstatus(dv, n, s)
    995  1.37.8.2  nathanw 	struct device *dv;
    996  1.37.8.2  nathanw 	int n;
    997  1.37.8.2  nathanw 	char *s;
    998  1.37.8.2  nathanw {
    999  1.37.8.2  nathanw 	struct fdc_softc *fdc = (void *)dv->dv_parent;
   1000  1.37.8.2  nathanw 	char bits[64];
   1001  1.37.8.2  nathanw 
   1002  1.37.8.2  nathanw 	if (n == 0) {
   1003  1.37.8.2  nathanw 		out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
   1004  1.37.8.2  nathanw 		(void) fdcresult(fdc);
   1005  1.37.8.2  nathanw 		n = 2;
   1006  1.37.8.2  nathanw 	}
   1007  1.37.8.2  nathanw 
   1008  1.37.8.2  nathanw 	printf("%s: %s: state %d", dv->dv_xname, s, fdc->sc_state);
   1009  1.37.8.2  nathanw 
   1010  1.37.8.2  nathanw 	switch (n) {
   1011  1.37.8.2  nathanw 	case 0:
   1012  1.37.8.2  nathanw 		printf("\n");
   1013  1.37.8.2  nathanw 		break;
   1014  1.37.8.2  nathanw 	case 2:
   1015  1.37.8.2  nathanw 		printf(" (st0 %s cyl %d)\n",
   1016  1.37.8.2  nathanw 		    bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
   1017  1.37.8.2  nathanw 		    bits, sizeof(bits)), fdc->sc_status[1]);
   1018  1.37.8.2  nathanw 		break;
   1019  1.37.8.2  nathanw 	case 7:
   1020  1.37.8.2  nathanw 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
   1021  1.37.8.2  nathanw 		    NE7_ST0BITS, bits, sizeof(bits)));
   1022  1.37.8.2  nathanw 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
   1023  1.37.8.2  nathanw 		    NE7_ST1BITS, bits, sizeof(bits)));
   1024  1.37.8.2  nathanw 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
   1025  1.37.8.2  nathanw 		    NE7_ST2BITS, bits, sizeof(bits)));
   1026  1.37.8.2  nathanw 		printf(" cyl %d head %d sec %d)\n",
   1027  1.37.8.2  nathanw 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
   1028  1.37.8.2  nathanw 		break;
   1029  1.37.8.2  nathanw #ifdef DIAGNOSTIC
   1030  1.37.8.2  nathanw 	default:
   1031  1.37.8.2  nathanw 		printf(" fdcstatus: weird size: %d\n", n);
   1032  1.37.8.2  nathanw 		break;
   1033  1.37.8.2  nathanw #endif
   1034  1.37.8.2  nathanw 	}
   1035  1.37.8.2  nathanw }
   1036  1.37.8.2  nathanw 
   1037  1.37.8.2  nathanw void
   1038  1.37.8.2  nathanw fdctimeout(arg)
   1039  1.37.8.2  nathanw 	void *arg;
   1040  1.37.8.2  nathanw {
   1041  1.37.8.2  nathanw 	struct fdc_softc *fdc = arg;
   1042  1.37.8.2  nathanw 	struct fd_softc *fd = fdc->sc_drives.tqh_first;
   1043  1.37.8.2  nathanw 	int s;
   1044  1.37.8.2  nathanw 
   1045  1.37.8.2  nathanw 	s = splbio();
   1046  1.37.8.2  nathanw 	fdcstatus(&fd->sc_dev, 0, "timeout");
   1047  1.37.8.2  nathanw 
   1048  1.37.8.4  nathanw 	if (BUFQ_PEEK(&fd->sc_q) != NULL)
   1049  1.37.8.2  nathanw 		fdc->sc_state++;
   1050  1.37.8.2  nathanw 	else
   1051  1.37.8.2  nathanw 		fdc->sc_state = DEVIDLE;
   1052  1.37.8.2  nathanw 
   1053  1.37.8.2  nathanw 	(void) fdcintr(fdc);
   1054  1.37.8.2  nathanw 	splx(s);
   1055  1.37.8.2  nathanw }
   1056  1.37.8.2  nathanw 
   1057  1.37.8.2  nathanw #if 0
   1058  1.37.8.2  nathanw void
   1059  1.37.8.2  nathanw fdcpseudointr(arg)
   1060  1.37.8.2  nathanw 	void *arg;
   1061  1.37.8.2  nathanw {
   1062  1.37.8.2  nathanw 	int s;
   1063  1.37.8.2  nathanw 	struct fdc_softc *fdc = arg;
   1064  1.37.8.2  nathanw 
   1065  1.37.8.2  nathanw 	/* just ensure it has the right spl */
   1066  1.37.8.2  nathanw 	s = splbio();
   1067  1.37.8.2  nathanw 	(void) fdcintr(fdc);
   1068  1.37.8.2  nathanw 	splx(s);
   1069  1.37.8.2  nathanw }
   1070  1.37.8.2  nathanw #endif
   1071  1.37.8.2  nathanw 
   1072  1.37.8.2  nathanw int
   1073  1.37.8.2  nathanw fdcintr(arg)
   1074  1.37.8.2  nathanw 	void *arg;
   1075  1.37.8.2  nathanw {
   1076  1.37.8.2  nathanw 	struct fdc_softc *fdc = arg;
   1077  1.37.8.2  nathanw #define	st0	fdc->sc_status[0]
   1078  1.37.8.2  nathanw #define	cyl	fdc->sc_status[1]
   1079  1.37.8.2  nathanw 	struct fd_softc *fd;
   1080  1.37.8.2  nathanw 	struct buf *bp;
   1081  1.37.8.2  nathanw 	bus_space_tag_t iot = fdc->sc_iot;
   1082  1.37.8.2  nathanw 	bus_space_handle_t ioh = fdc->sc_ioh;
   1083  1.37.8.2  nathanw 	int read, head, sec, pos, i, sectrac, nblks;
   1084  1.37.8.2  nathanw 	int	tmp;
   1085  1.37.8.2  nathanw 	struct fd_type *type;
   1086  1.37.8.2  nathanw 
   1087  1.37.8.2  nathanw loop:
   1088  1.37.8.2  nathanw 	fd = fdc->sc_drives.tqh_first;
   1089  1.37.8.2  nathanw 	if (fd == NULL) {
   1090  1.37.8.2  nathanw 		DPRINTF(("fdcintr: set DEVIDLE\n"));
   1091  1.37.8.2  nathanw 		if (fdc->sc_state == DEVIDLE) {
   1092  1.37.8.2  nathanw 			if (intio_get_sicilian_intr() & SICILIAN_STAT_FDC) {
   1093  1.37.8.2  nathanw 				out_fdc(iot, ioh, NE7CMD_SENSEI);
   1094  1.37.8.2  nathanw 				if ((tmp = fdcresult(fdc)) != 2 ||
   1095  1.37.8.2  nathanw 				    (st0 & 0xf8) != 0x20) {
   1096  1.37.8.2  nathanw 					goto loop;
   1097  1.37.8.2  nathanw 				}
   1098  1.37.8.2  nathanw 			}
   1099  1.37.8.2  nathanw 		}
   1100  1.37.8.2  nathanw 		/* no drives waiting; end */
   1101  1.37.8.2  nathanw 		fdc->sc_state = DEVIDLE;
   1102  1.37.8.2  nathanw  		return 1;
   1103  1.37.8.2  nathanw 	}
   1104  1.37.8.2  nathanw 
   1105  1.37.8.2  nathanw 	/* Is there a transfer to this drive?  If not, deactivate drive. */
   1106  1.37.8.4  nathanw 	bp = BUFQ_PEEK(&fd->sc_q);
   1107  1.37.8.2  nathanw 	if (bp == NULL) {
   1108  1.37.8.2  nathanw 		fd->sc_ops = 0;
   1109  1.37.8.2  nathanw 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
   1110  1.37.8.2  nathanw 		fd->sc_active = 0;
   1111  1.37.8.2  nathanw 		goto loop;
   1112  1.37.8.2  nathanw 	}
   1113  1.37.8.2  nathanw 
   1114  1.37.8.2  nathanw 	switch (fdc->sc_state) {
   1115  1.37.8.2  nathanw 	case DEVIDLE:
   1116  1.37.8.2  nathanw 		DPRINTF(("fdcintr: in DEVIDLE\n"));
   1117  1.37.8.2  nathanw 		fdc->sc_errors = 0;
   1118  1.37.8.2  nathanw 		fd->sc_skip = 0;
   1119  1.37.8.2  nathanw 		fd->sc_bcount = bp->b_bcount;
   1120  1.37.8.2  nathanw 		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
   1121  1.37.8.2  nathanw 		callout_stop(&fd->sc_motoroff_ch);
   1122  1.37.8.2  nathanw 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
   1123  1.37.8.2  nathanw 			fdc->sc_state = MOTORWAIT;
   1124  1.37.8.2  nathanw 			return 1;
   1125  1.37.8.2  nathanw 		}
   1126  1.37.8.2  nathanw 		if ((fd->sc_flags & FD_MOTOR) == 0) {
   1127  1.37.8.2  nathanw 			/* Turn on the motor */
   1128  1.37.8.2  nathanw 			/* being careful about other drives. */
   1129  1.37.8.2  nathanw 			for (i = 0; i < 4; i++) {
   1130  1.37.8.2  nathanw 				struct fd_softc *ofd = fdc->sc_fd[i];
   1131  1.37.8.2  nathanw 				if (ofd && ofd->sc_flags & FD_MOTOR) {
   1132  1.37.8.2  nathanw 					callout_stop(&ofd->sc_motoroff_ch);
   1133  1.37.8.6  nathanw 					ofd->sc_flags &=
   1134  1.37.8.6  nathanw 						~(FD_MOTOR | FD_MOTOR_WAIT);
   1135  1.37.8.2  nathanw 					break;
   1136  1.37.8.2  nathanw 				}
   1137  1.37.8.2  nathanw 			}
   1138  1.37.8.2  nathanw 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
   1139  1.37.8.2  nathanw 			fd_set_motor(fdc, 0);
   1140  1.37.8.2  nathanw 			fdc->sc_state = MOTORWAIT;
   1141  1.37.8.2  nathanw 			/* allow .5s for motor to stabilize */
   1142  1.37.8.2  nathanw 			callout_reset(&fd->sc_motoron_ch, hz / 2,
   1143  1.37.8.2  nathanw 			    fd_motor_on, fd);
   1144  1.37.8.2  nathanw 			return 1;
   1145  1.37.8.2  nathanw 		}
   1146  1.37.8.2  nathanw 		/* Make sure the right drive is selected. */
   1147  1.37.8.2  nathanw 		fd_set_motor(fdc, 0);
   1148  1.37.8.2  nathanw 
   1149  1.37.8.2  nathanw 		/* fall through */
   1150  1.37.8.2  nathanw 	case DOSEEK:
   1151  1.37.8.2  nathanw 	doseek:
   1152  1.37.8.2  nathanw 		DPRINTF(("fdcintr: in DOSEEK\n"));
   1153  1.37.8.2  nathanw 		if (fd->sc_cylin == bp->b_cylinder)
   1154  1.37.8.2  nathanw 			goto doio;
   1155  1.37.8.2  nathanw 
   1156  1.37.8.2  nathanw 		out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
   1157  1.37.8.2  nathanw 		out_fdc(iot, ioh, 0xd0);	/* XXX const */
   1158  1.37.8.2  nathanw 		out_fdc(iot, ioh, 0x10);
   1159  1.37.8.2  nathanw 
   1160  1.37.8.2  nathanw 		out_fdc(iot, ioh, NE7CMD_SEEK);	/* seek function */
   1161  1.37.8.2  nathanw 		out_fdc(iot, ioh, fd->sc_drive);	/* drive number */
   1162  1.37.8.2  nathanw 		out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
   1163  1.37.8.2  nathanw 
   1164  1.37.8.2  nathanw 		fd->sc_cylin = -1;
   1165  1.37.8.2  nathanw 		fdc->sc_state = SEEKWAIT;
   1166  1.37.8.2  nathanw 
   1167  1.37.8.2  nathanw 		fd->sc_dk.dk_seek++;
   1168  1.37.8.2  nathanw 		disk_busy(&fd->sc_dk);
   1169  1.37.8.2  nathanw 
   1170  1.37.8.2  nathanw 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
   1171  1.37.8.2  nathanw 		return 1;
   1172  1.37.8.2  nathanw 
   1173  1.37.8.2  nathanw 	case DOIO:
   1174  1.37.8.2  nathanw 	doio:
   1175  1.37.8.2  nathanw 		DPRINTF(("fdcintr: DOIO: "));
   1176  1.37.8.2  nathanw 		type = fd->sc_type;
   1177  1.37.8.2  nathanw 		sectrac = type->sectrac;
   1178  1.37.8.2  nathanw 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
   1179  1.37.8.2  nathanw 		sec = pos / (1 << (type->secsize - 2));
   1180  1.37.8.2  nathanw 		if (type->secsize == 2) {
   1181  1.37.8.2  nathanw 			fd->sc_part = SEC_P11;
   1182  1.37.8.2  nathanw 			nblks = (sectrac - sec) << (type->secsize - 2);
   1183  1.37.8.2  nathanw 			nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
   1184  1.37.8.2  nathanw 			DPRINTF(("nblks(0)"));
   1185  1.37.8.2  nathanw 		} else if ((fd->sc_blkno % 2) == 0) {
   1186  1.37.8.2  nathanw 			if (fd->sc_bcount & 0x00000200) {
   1187  1.37.8.2  nathanw 				if (fd->sc_bcount == FDC_BSIZE) {
   1188  1.37.8.2  nathanw 					fd->sc_part = SEC_P10;
   1189  1.37.8.2  nathanw 					nblks = 1;
   1190  1.37.8.2  nathanw 					DPRINTF(("nblks(1)"));
   1191  1.37.8.2  nathanw 				} else {
   1192  1.37.8.2  nathanw 					fd->sc_part = SEC_P11;
   1193  1.37.8.2  nathanw 					nblks = (sectrac - sec) * 2;
   1194  1.37.8.2  nathanw 					nblks = min(nblks, fd->sc_bcount
   1195  1.37.8.2  nathanw 						    / FDC_BSIZE - 1);
   1196  1.37.8.2  nathanw 					DPRINTF(("nblks(2)"));
   1197  1.37.8.2  nathanw 				}
   1198  1.37.8.2  nathanw 			} else {
   1199  1.37.8.2  nathanw 				fd->sc_part = SEC_P11;
   1200  1.37.8.2  nathanw 				nblks = (sectrac - sec)
   1201  1.37.8.2  nathanw 					<< (type->secsize - 2);
   1202  1.37.8.2  nathanw 				nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
   1203  1.37.8.2  nathanw 				DPRINTF(("nblks(3)"));
   1204  1.37.8.2  nathanw 			}
   1205  1.37.8.2  nathanw 		} else {
   1206  1.37.8.2  nathanw 			fd->sc_part = SEC_P01;
   1207  1.37.8.2  nathanw 			nblks = 1;
   1208  1.37.8.2  nathanw 			DPRINTF(("nblks(4)"));
   1209  1.37.8.2  nathanw 		}
   1210  1.37.8.2  nathanw 		nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
   1211  1.37.8.2  nathanw 		DPRINTF((" %d\n", nblks));
   1212  1.37.8.2  nathanw 		fd->sc_nblks = nblks;
   1213  1.37.8.2  nathanw 		fd->sc_nbytes = nblks * FDC_BSIZE;
   1214  1.37.8.2  nathanw 		head = (fd->sc_blkno
   1215  1.37.8.2  nathanw 			% (type->seccyl * (1 << (type->secsize - 2))))
   1216  1.37.8.2  nathanw 			 / (type->sectrac * (1 << (type->secsize - 2)));
   1217  1.37.8.2  nathanw 
   1218  1.37.8.2  nathanw #ifdef DIAGNOSTIC
   1219  1.37.8.2  nathanw 		{int block;
   1220  1.37.8.2  nathanw 		 block = ((fd->sc_cylin * type->heads + head) * type->sectrac
   1221  1.37.8.2  nathanw 			  + sec) * (1 << (type->secsize - 2));
   1222  1.37.8.2  nathanw 		 block += (fd->sc_part == SEC_P01) ? 1 : 0;
   1223  1.37.8.2  nathanw 		 if (block != fd->sc_blkno) {
   1224  1.37.8.6  nathanw 			 printf("C H R N: %d %d %d %d\n",
   1225  1.37.8.6  nathanw 				fd->sc_cylin, head, sec, type->secsize);
   1226  1.37.8.6  nathanw 			 printf("fdcintr: doio: block %d != blkno %d\n",
   1227  1.37.8.6  nathanw 				block, fd->sc_blkno);
   1228  1.37.8.2  nathanw #ifdef DDB
   1229  1.37.8.2  nathanw 			 Debugger();
   1230  1.37.8.2  nathanw #endif
   1231  1.37.8.6  nathanw 		 }
   1232  1.37.8.6  nathanw 		}
   1233  1.37.8.2  nathanw #endif
   1234  1.37.8.2  nathanw 		read = bp->b_flags & B_READ;
   1235  1.37.8.6  nathanw 		DPRINTF(("fdcintr: %s drive %d track %d "
   1236  1.37.8.6  nathanw 		         "head %d sec %d nblks %d, skip %d\n",
   1237  1.37.8.2  nathanw 			 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
   1238  1.37.8.2  nathanw 			 head, sec, nblks, fd->sc_skip));
   1239  1.37.8.2  nathanw 		DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
   1240  1.37.8.2  nathanw 			 type->secsize));
   1241  1.37.8.2  nathanw 
   1242  1.37.8.2  nathanw 		if (fd->sc_part != SEC_P11)
   1243  1.37.8.2  nathanw 			goto docopy;
   1244  1.37.8.2  nathanw 
   1245  1.37.8.2  nathanw 		fdc_dmastart(fdc,
   1246  1.37.8.2  nathanw 			     read, bp->b_data + fd->sc_skip, fd->sc_nbytes);
   1247  1.37.8.2  nathanw 		if (read)
   1248  1.37.8.2  nathanw 			out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
   1249  1.37.8.2  nathanw 		else
   1250  1.37.8.2  nathanw 			out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
   1251  1.37.8.2  nathanw 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1252  1.37.8.2  nathanw 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
   1253  1.37.8.2  nathanw 		out_fdc(iot, ioh, head);
   1254  1.37.8.2  nathanw 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
   1255  1.37.8.2  nathanw 		out_fdc(iot, ioh, type->secsize);	/* sector size */
   1256  1.37.8.2  nathanw 		out_fdc(iot, ioh, type->sectrac);	/* sectors/track */
   1257  1.37.8.2  nathanw 		out_fdc(iot, ioh, type->gap1);		/* gap1 size */
   1258  1.37.8.2  nathanw 		out_fdc(iot, ioh, type->datalen);	/* data length */
   1259  1.37.8.2  nathanw 		fdc->sc_state = IOCOMPLETE;
   1260  1.37.8.2  nathanw 
   1261  1.37.8.2  nathanw 		disk_busy(&fd->sc_dk);
   1262  1.37.8.2  nathanw 
   1263  1.37.8.2  nathanw 		/* allow 2 seconds for operation */
   1264  1.37.8.2  nathanw 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1265  1.37.8.2  nathanw 		return 1;				/* will return later */
   1266  1.37.8.2  nathanw 
   1267  1.37.8.2  nathanw 	case DOCOPY:
   1268  1.37.8.2  nathanw 	docopy:
   1269  1.37.8.2  nathanw 		DPRINTF(("fdcintr: DOCOPY:\n"));
   1270  1.37.8.2  nathanw 		fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024);
   1271  1.37.8.2  nathanw 		out_fdc(iot, ioh, NE7CMD_READ);		/* READ */
   1272  1.37.8.2  nathanw 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1273  1.37.8.2  nathanw 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
   1274  1.37.8.2  nathanw 		out_fdc(iot, ioh, head);
   1275  1.37.8.2  nathanw 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
   1276  1.37.8.2  nathanw 		out_fdc(iot, ioh, type->secsize);	/* sector size */
   1277  1.37.8.2  nathanw 		out_fdc(iot, ioh, type->sectrac);	/* sectors/track */
   1278  1.37.8.2  nathanw 		out_fdc(iot, ioh, type->gap1);		/* gap1 size */
   1279  1.37.8.2  nathanw 		out_fdc(iot, ioh, type->datalen);	/* data length */
   1280  1.37.8.2  nathanw 		fdc->sc_state = COPYCOMPLETE;
   1281  1.37.8.2  nathanw 		/* allow 2 seconds for operation */
   1282  1.37.8.2  nathanw 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1283  1.37.8.2  nathanw 		return 1;				/* will return later */
   1284  1.37.8.2  nathanw 
   1285  1.37.8.2  nathanw 	case DOIOHALF:
   1286  1.37.8.2  nathanw 	doiohalf:
   1287  1.37.8.2  nathanw 		DPRINTF((" DOIOHALF:\n"));
   1288  1.37.8.2  nathanw 
   1289  1.37.8.2  nathanw #ifdef DIAGNOSTIC
   1290  1.37.8.2  nathanw 		type = fd->sc_type;
   1291  1.37.8.2  nathanw 		sectrac = type->sectrac;
   1292  1.37.8.2  nathanw 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
   1293  1.37.8.2  nathanw 		sec = pos / (1 << (type->secsize - 2));
   1294  1.37.8.2  nathanw 		head = (fd->sc_blkno
   1295  1.37.8.2  nathanw 			% (type->seccyl * (1 << (type->secsize - 2))))
   1296  1.37.8.2  nathanw 			 / (type->sectrac * (1 << (type->secsize - 2)));
   1297  1.37.8.2  nathanw 		{int block;
   1298  1.37.8.6  nathanw 		 block = ((fd->sc_cylin * type->heads + head) *
   1299  1.37.8.6  nathanw 			 type->sectrac + sec)
   1300  1.37.8.2  nathanw 			 * (1 << (type->secsize - 2));
   1301  1.37.8.2  nathanw 		 block += (fd->sc_part == SEC_P01) ? 1 : 0;
   1302  1.37.8.2  nathanw 		 if (block != fd->sc_blkno) {
   1303  1.37.8.6  nathanw 			 printf("fdcintr: block %d != blkno %d\n",
   1304  1.37.8.6  nathanw 				block, fd->sc_blkno);
   1305  1.37.8.2  nathanw #ifdef DDB
   1306  1.37.8.2  nathanw 			 Debugger();
   1307  1.37.8.2  nathanw #endif
   1308  1.37.8.6  nathanw 		 }
   1309  1.37.8.6  nathanw 		}
   1310  1.37.8.2  nathanw #endif
   1311  1.37.8.2  nathanw 		if ((read = bp->b_flags & B_READ)) {
   1312  1.37.8.2  nathanw 			memcpy(bp->b_data + fd->sc_skip, fd->sc_copybuf
   1313  1.37.8.2  nathanw 			    + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
   1314  1.37.8.2  nathanw 			    FDC_BSIZE);
   1315  1.37.8.2  nathanw 			fdc->sc_state = IOCOMPLETE;
   1316  1.37.8.2  nathanw 			goto iocomplete2;
   1317  1.37.8.2  nathanw 		} else {
   1318  1.37.8.2  nathanw 			memcpy(fd->sc_copybuf
   1319  1.37.8.2  nathanw 			    + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
   1320  1.37.8.2  nathanw 			    bp->b_data + fd->sc_skip, FDC_BSIZE);
   1321  1.37.8.2  nathanw 			fdc_dmastart(fdc, read, fd->sc_copybuf, 1024);
   1322  1.37.8.2  nathanw 		}
   1323  1.37.8.2  nathanw 		out_fdc(iot, ioh, NE7CMD_WRITE);	/* WRITE */
   1324  1.37.8.2  nathanw 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1325  1.37.8.2  nathanw 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
   1326  1.37.8.2  nathanw 		out_fdc(iot, ioh, head);
   1327  1.37.8.2  nathanw 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
   1328  1.37.8.2  nathanw 		out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */
   1329  1.37.8.2  nathanw 		out_fdc(iot, ioh, sectrac);		/* sectors/track */
   1330  1.37.8.2  nathanw 		out_fdc(iot, ioh, fd->sc_type->gap1);	/* gap1 size */
   1331  1.37.8.2  nathanw 		out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */
   1332  1.37.8.2  nathanw 		fdc->sc_state = IOCOMPLETE;
   1333  1.37.8.2  nathanw 		/* allow 2 seconds for operation */
   1334  1.37.8.2  nathanw 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1335  1.37.8.2  nathanw 		return 1;				/* will return later */
   1336  1.37.8.2  nathanw 
   1337  1.37.8.2  nathanw 	case SEEKWAIT:
   1338  1.37.8.2  nathanw 		callout_stop(&fdc->sc_timo_ch);
   1339  1.37.8.2  nathanw 		fdc->sc_state = SEEKCOMPLETE;
   1340  1.37.8.2  nathanw 		/* allow 1/50 second for heads to settle */
   1341  1.37.8.2  nathanw #if 0
   1342  1.37.8.2  nathanw 		callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
   1343  1.37.8.2  nathanw #endif
   1344  1.37.8.2  nathanw 		return 1;
   1345  1.37.8.2  nathanw 
   1346  1.37.8.2  nathanw 	case SEEKCOMPLETE:
   1347  1.37.8.2  nathanw 		/* Make sure seek really happened */
   1348  1.37.8.2  nathanw 		DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
   1349  1.37.8.2  nathanw 			 bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts)));
   1350  1.37.8.2  nathanw 		out_fdc(iot, ioh, NE7CMD_SENSEI);
   1351  1.37.8.2  nathanw 		tmp = fdcresult(fdc);
   1352  1.37.8.2  nathanw 		if ((st0 & 0xf8) == 0xc0) {
   1353  1.37.8.2  nathanw 			DPRINTF(("fdcintr: first seek!\n"));
   1354  1.37.8.2  nathanw 			fdc->sc_state = DORECAL;
   1355  1.37.8.2  nathanw 			goto loop;
   1356  1.37.8.2  nathanw 		} else if (tmp != 2 ||
   1357  1.37.8.2  nathanw 			   (st0 & 0xf8) != 0x20 ||
   1358  1.37.8.2  nathanw 			   cyl != bp->b_cylinder) {
   1359  1.37.8.2  nathanw #ifdef FDDEBUG
   1360  1.37.8.2  nathanw 			fdcstatus(&fd->sc_dev, 2, "seek failed");
   1361  1.37.8.2  nathanw #endif
   1362  1.37.8.2  nathanw 			fdcretry(fdc);
   1363  1.37.8.2  nathanw 			goto loop;
   1364  1.37.8.2  nathanw 		}
   1365  1.37.8.2  nathanw 		fd->sc_cylin = bp->b_cylinder;
   1366  1.37.8.2  nathanw 		goto doio;
   1367  1.37.8.2  nathanw 
   1368  1.37.8.2  nathanw 	case IOTIMEDOUT:
   1369  1.37.8.2  nathanw #if 0
   1370  1.37.8.2  nathanw 		isa_dmaabort(fdc->sc_drq);
   1371  1.37.8.2  nathanw #endif
   1372  1.37.8.2  nathanw 	case SEEKTIMEDOUT:
   1373  1.37.8.2  nathanw 	case RECALTIMEDOUT:
   1374  1.37.8.2  nathanw 	case RESETTIMEDOUT:
   1375  1.37.8.2  nathanw 		fdcretry(fdc);
   1376  1.37.8.2  nathanw 		goto loop;
   1377  1.37.8.2  nathanw 
   1378  1.37.8.2  nathanw 	case IOCOMPLETE: /* IO DONE, post-analyze */
   1379  1.37.8.2  nathanw 		callout_stop(&fdc->sc_timo_ch);
   1380  1.37.8.2  nathanw 		DPRINTF(("fdcintr: in IOCOMPLETE\n"));
   1381  1.37.8.2  nathanw 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
   1382  1.37.8.2  nathanw 			printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
   1383  1.37.8.2  nathanw #if 0
   1384  1.37.8.2  nathanw 			isa_dmaabort(fdc->sc_drq);
   1385  1.37.8.2  nathanw #endif
   1386  1.37.8.2  nathanw 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
   1387  1.37.8.2  nathanw 				  "read failed" : "write failed");
   1388  1.37.8.2  nathanw 			printf("blkno %d nblks %d\n",
   1389  1.37.8.2  nathanw 			    fd->sc_blkno, fd->sc_nblks);
   1390  1.37.8.2  nathanw 			fdcretry(fdc);
   1391  1.37.8.2  nathanw 			goto loop;
   1392  1.37.8.2  nathanw 		}
   1393  1.37.8.2  nathanw #if 0
   1394  1.37.8.2  nathanw 		isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
   1395  1.37.8.2  nathanw 		    nblks * FDC_BSIZE, fdc->sc_drq);
   1396  1.37.8.2  nathanw #endif
   1397  1.37.8.2  nathanw 	iocomplete2:
   1398  1.37.8.2  nathanw 		if (fdc->sc_errors) {
   1399  1.37.8.2  nathanw 			diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
   1400  1.37.8.2  nathanw 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
   1401  1.37.8.2  nathanw 			printf("\n");
   1402  1.37.8.2  nathanw 			fdc->sc_errors = 0;
   1403  1.37.8.2  nathanw 		}
   1404  1.37.8.2  nathanw 		fd->sc_blkno += fd->sc_nblks;
   1405  1.37.8.2  nathanw 		fd->sc_skip += fd->sc_nbytes;
   1406  1.37.8.2  nathanw 		fd->sc_bcount -= fd->sc_nbytes;
   1407  1.37.8.2  nathanw 		DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
   1408  1.37.8.2  nathanw 		if (fd->sc_bcount > 0) {
   1409  1.37.8.2  nathanw 			bp->b_cylinder = fd->sc_blkno
   1410  1.37.8.2  nathanw 				/ (fd->sc_type->seccyl
   1411  1.37.8.2  nathanw 				   * (1 << (fd->sc_type->secsize - 2)));
   1412  1.37.8.2  nathanw 			goto doseek;
   1413  1.37.8.2  nathanw 		}
   1414  1.37.8.2  nathanw 		fdfinish(fd, bp);
   1415  1.37.8.2  nathanw 		goto loop;
   1416  1.37.8.2  nathanw 
   1417  1.37.8.2  nathanw 	case COPYCOMPLETE: /* IO DONE, post-analyze */
   1418  1.37.8.2  nathanw 		DPRINTF(("fdcintr: COPYCOMPLETE:"));
   1419  1.37.8.2  nathanw 		callout_stop(&fdc->sc_timo_ch);
   1420  1.37.8.2  nathanw 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
   1421  1.37.8.2  nathanw 			printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
   1422  1.37.8.2  nathanw #if 0
   1423  1.37.8.2  nathanw 			isa_dmaabort(fdc->sc_drq);
   1424  1.37.8.2  nathanw #endif
   1425  1.37.8.2  nathanw 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
   1426  1.37.8.2  nathanw 				  "read failed" : "write failed");
   1427  1.37.8.2  nathanw 			printf("blkno %d nblks %d\n",
   1428  1.37.8.2  nathanw 			    fd->sc_blkno, fd->sc_nblks);
   1429  1.37.8.2  nathanw 			fdcretry(fdc);
   1430  1.37.8.2  nathanw 			goto loop;
   1431  1.37.8.2  nathanw 		}
   1432  1.37.8.2  nathanw 		goto doiohalf;
   1433  1.37.8.2  nathanw 
   1434  1.37.8.2  nathanw 	case DORESET:
   1435  1.37.8.2  nathanw 		DPRINTF(("fdcintr: in DORESET\n"));
   1436  1.37.8.2  nathanw 		/* try a reset, keep motor on */
   1437  1.37.8.2  nathanw 		fd_set_motor(fdc, 1);
   1438  1.37.8.2  nathanw 		DELAY(100);
   1439  1.37.8.2  nathanw 		fd_set_motor(fdc, 0);
   1440  1.37.8.2  nathanw 		fdc->sc_state = RESETCOMPLETE;
   1441  1.37.8.2  nathanw 		callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
   1442  1.37.8.2  nathanw 		return 1;			/* will return later */
   1443  1.37.8.2  nathanw 
   1444  1.37.8.2  nathanw 	case RESETCOMPLETE:
   1445  1.37.8.2  nathanw 		DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
   1446  1.37.8.2  nathanw 		callout_stop(&fdc->sc_timo_ch);
   1447  1.37.8.2  nathanw 		/* clear the controller output buffer */
   1448  1.37.8.2  nathanw 		for (i = 0; i < 4; i++) {
   1449  1.37.8.2  nathanw 			out_fdc(iot, ioh, NE7CMD_SENSEI);
   1450  1.37.8.2  nathanw 			(void) fdcresult(fdc);
   1451  1.37.8.2  nathanw 		}
   1452  1.37.8.2  nathanw 
   1453  1.37.8.2  nathanw 		/* fall through */
   1454  1.37.8.2  nathanw 	case DORECAL:
   1455  1.37.8.2  nathanw 		DPRINTF(("fdcintr: in DORECAL\n"));
   1456  1.37.8.6  nathanw 		out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
   1457  1.37.8.2  nathanw 		out_fdc(iot, ioh, fd->sc_drive);
   1458  1.37.8.2  nathanw 		fdc->sc_state = RECALWAIT;
   1459  1.37.8.2  nathanw 		callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
   1460  1.37.8.2  nathanw 		return 1;			/* will return later */
   1461  1.37.8.2  nathanw 
   1462  1.37.8.2  nathanw 	case RECALWAIT:
   1463  1.37.8.2  nathanw 		DPRINTF(("fdcintr: in RECALWAIT\n"));
   1464  1.37.8.2  nathanw 		callout_stop(&fdc->sc_timo_ch);
   1465  1.37.8.2  nathanw 		fdc->sc_state = RECALCOMPLETE;
   1466  1.37.8.2  nathanw 		/* allow 1/30 second for heads to settle */
   1467  1.37.8.2  nathanw #if 0
   1468  1.37.8.2  nathanw 		callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
   1469  1.37.8.2  nathanw #endif
   1470  1.37.8.2  nathanw 		return 1;			/* will return later */
   1471  1.37.8.2  nathanw 
   1472  1.37.8.2  nathanw 	case RECALCOMPLETE:
   1473  1.37.8.2  nathanw 		DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
   1474  1.37.8.2  nathanw 		out_fdc(iot, ioh, NE7CMD_SENSEI);
   1475  1.37.8.2  nathanw 		tmp = fdcresult(fdc);
   1476  1.37.8.2  nathanw 		if ((st0 & 0xf8) == 0xc0) {
   1477  1.37.8.2  nathanw 			DPRINTF(("fdcintr: first seek!\n"));
   1478  1.37.8.2  nathanw 			fdc->sc_state = DORECAL;
   1479  1.37.8.2  nathanw 			goto loop;
   1480  1.37.8.2  nathanw 		} else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
   1481  1.37.8.2  nathanw #ifdef FDDEBUG
   1482  1.37.8.2  nathanw 			fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
   1483  1.37.8.2  nathanw #endif
   1484  1.37.8.2  nathanw 			fdcretry(fdc);
   1485  1.37.8.2  nathanw 			goto loop;
   1486  1.37.8.2  nathanw 		}
   1487  1.37.8.2  nathanw 		fd->sc_cylin = 0;
   1488  1.37.8.2  nathanw 		goto doseek;
   1489  1.37.8.2  nathanw 
   1490  1.37.8.2  nathanw 	case MOTORWAIT:
   1491  1.37.8.2  nathanw 		if (fd->sc_flags & FD_MOTOR_WAIT)
   1492  1.37.8.2  nathanw 			return 1;		/* time's not up yet */
   1493  1.37.8.2  nathanw 		goto doseek;
   1494  1.37.8.2  nathanw 
   1495  1.37.8.2  nathanw 	default:
   1496  1.37.8.2  nathanw 		fdcstatus(&fd->sc_dev, 0, "stray interrupt");
   1497  1.37.8.2  nathanw 		return 1;
   1498  1.37.8.2  nathanw 	}
   1499  1.37.8.2  nathanw #ifdef DIAGNOSTIC
   1500  1.37.8.2  nathanw 	panic("fdcintr: impossible");
   1501  1.37.8.2  nathanw #endif
   1502  1.37.8.2  nathanw #undef	st0
   1503  1.37.8.2  nathanw #undef	cyl
   1504  1.37.8.2  nathanw }
   1505  1.37.8.2  nathanw 
   1506  1.37.8.2  nathanw void
   1507  1.37.8.2  nathanw fdcretry(fdc)
   1508  1.37.8.2  nathanw 	struct fdc_softc *fdc;
   1509  1.37.8.2  nathanw {
   1510  1.37.8.2  nathanw 	struct fd_softc *fd;
   1511  1.37.8.2  nathanw 	struct buf *bp;
   1512  1.37.8.2  nathanw 	char bits[64];
   1513  1.37.8.2  nathanw 
   1514  1.37.8.2  nathanw 	DPRINTF(("fdcretry:\n"));
   1515  1.37.8.2  nathanw 	fd = fdc->sc_drives.tqh_first;
   1516  1.37.8.4  nathanw 	bp = BUFQ_PEEK(&fd->sc_q);
   1517  1.37.8.2  nathanw 
   1518  1.37.8.2  nathanw 	switch (fdc->sc_errors) {
   1519  1.37.8.2  nathanw 	case 0:
   1520  1.37.8.2  nathanw 		/* try again */
   1521  1.37.8.2  nathanw 		fdc->sc_state = SEEKCOMPLETE;
   1522  1.37.8.2  nathanw 		break;
   1523  1.37.8.2  nathanw 
   1524  1.37.8.2  nathanw 	case 1: case 2: case 3:
   1525  1.37.8.2  nathanw 		/* didn't work; try recalibrating */
   1526  1.37.8.2  nathanw 		fdc->sc_state = DORECAL;
   1527  1.37.8.2  nathanw 		break;
   1528  1.37.8.2  nathanw 
   1529  1.37.8.2  nathanw 	case 4:
   1530  1.37.8.2  nathanw 		/* still no go; reset the bastard */
   1531  1.37.8.2  nathanw 		fdc->sc_state = DORESET;
   1532  1.37.8.2  nathanw 		break;
   1533  1.37.8.2  nathanw 
   1534  1.37.8.2  nathanw 	default:
   1535  1.37.8.2  nathanw 		diskerr(bp, "fd", "hard error", LOG_PRINTF,
   1536  1.37.8.2  nathanw 			fd->sc_skip, (struct disklabel *)NULL);
   1537  1.37.8.2  nathanw 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
   1538  1.37.8.2  nathanw 						    NE7_ST0BITS, bits,
   1539  1.37.8.2  nathanw 						    sizeof(bits)));
   1540  1.37.8.2  nathanw 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
   1541  1.37.8.2  nathanw 						   NE7_ST1BITS, bits,
   1542  1.37.8.2  nathanw 						   sizeof(bits)));
   1543  1.37.8.2  nathanw 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
   1544  1.37.8.2  nathanw 						   NE7_ST2BITS, bits,
   1545  1.37.8.2  nathanw 						   sizeof(bits)));
   1546  1.37.8.2  nathanw 		printf(" cyl %d head %d sec %d)\n",
   1547  1.37.8.2  nathanw 		       fdc->sc_status[3],
   1548  1.37.8.2  nathanw 		       fdc->sc_status[4],
   1549  1.37.8.2  nathanw 		       fdc->sc_status[5]);
   1550  1.37.8.2  nathanw 
   1551  1.37.8.2  nathanw 		bp->b_flags |= B_ERROR;
   1552  1.37.8.2  nathanw 		bp->b_error = EIO;
   1553  1.37.8.2  nathanw 		fdfinish(fd, bp);
   1554  1.37.8.2  nathanw 	}
   1555  1.37.8.2  nathanw 	fdc->sc_errors++;
   1556  1.37.8.2  nathanw }
   1557  1.37.8.2  nathanw 
   1558  1.37.8.2  nathanw int
   1559  1.37.8.2  nathanw fdioctl(dev, cmd, addr, flag, p)
   1560  1.37.8.2  nathanw 	dev_t dev;
   1561  1.37.8.2  nathanw 	u_long cmd;
   1562  1.37.8.2  nathanw 	caddr_t addr;
   1563  1.37.8.2  nathanw 	int flag;
   1564  1.37.8.2  nathanw 	struct proc *p;
   1565  1.37.8.2  nathanw {
   1566  1.37.8.2  nathanw 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
   1567  1.37.8.2  nathanw 	struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
   1568  1.37.8.2  nathanw 	int unit = FDUNIT(dev);
   1569  1.37.8.2  nathanw 	int part = DISKPART(dev);
   1570  1.37.8.2  nathanw 	struct disklabel buffer;
   1571  1.37.8.2  nathanw 	int error;
   1572  1.37.8.2  nathanw 
   1573  1.37.8.2  nathanw 	DPRINTF(("fdioctl:\n"));
   1574  1.37.8.2  nathanw 	switch (cmd) {
   1575  1.37.8.2  nathanw 	case DIOCGDINFO:
   1576  1.37.8.2  nathanw #if 1
   1577  1.37.8.2  nathanw 		*(struct disklabel *)addr = *(fd->sc_dk.dk_label);
   1578  1.37.8.2  nathanw 		return(0);
   1579  1.37.8.2  nathanw #else
   1580  1.37.8.2  nathanw 		memset(&buffer, 0, sizeof(buffer));
   1581  1.37.8.2  nathanw 
   1582  1.37.8.2  nathanw 		buffer.d_secpercyl = fd->sc_type->seccyl;
   1583  1.37.8.2  nathanw 		buffer.d_type = DTYPE_FLOPPY;
   1584  1.37.8.2  nathanw 		buffer.d_secsize = 128 << fd->sc_type->secsize;
   1585  1.37.8.2  nathanw 
   1586  1.37.8.2  nathanw 		if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
   1587  1.37.8.2  nathanw 			return EINVAL;
   1588  1.37.8.2  nathanw 
   1589  1.37.8.2  nathanw 		*(struct disklabel *)addr = buffer;
   1590  1.37.8.2  nathanw 		return 0;
   1591  1.37.8.2  nathanw #endif
   1592  1.37.8.2  nathanw 
   1593  1.37.8.2  nathanw 	case DIOCGPART:
   1594  1.37.8.2  nathanw 		((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
   1595  1.37.8.2  nathanw 		((struct partinfo *)addr)->part =
   1596  1.37.8.2  nathanw 		    &fd->sc_dk.dk_label->d_partitions[part];
   1597  1.37.8.2  nathanw 		return(0);
   1598  1.37.8.2  nathanw 
   1599  1.37.8.2  nathanw 	case DIOCWLABEL:
   1600  1.37.8.2  nathanw 		if ((flag & FWRITE) == 0)
   1601  1.37.8.2  nathanw 			return EBADF;
   1602  1.37.8.2  nathanw 		/* XXX do something */
   1603  1.37.8.2  nathanw 		return 0;
   1604  1.37.8.2  nathanw 
   1605  1.37.8.2  nathanw 	case DIOCWDINFO:
   1606  1.37.8.2  nathanw 		if ((flag & FWRITE) == 0)
   1607  1.37.8.2  nathanw 			return EBADF;
   1608  1.37.8.2  nathanw 
   1609  1.37.8.6  nathanw 		error = setdisklabel(&buffer, (struct disklabel *)addr,
   1610  1.37.8.6  nathanw 		                     0, NULL);
   1611  1.37.8.2  nathanw 		if (error)
   1612  1.37.8.2  nathanw 			return error;
   1613  1.37.8.2  nathanw 
   1614  1.37.8.2  nathanw 		error = writedisklabel(dev, fdstrategy, &buffer, NULL);
   1615  1.37.8.2  nathanw 		return error;
   1616  1.37.8.2  nathanw 
   1617  1.37.8.2  nathanw 	case DIOCLOCK:
   1618  1.37.8.2  nathanw 		/*
   1619  1.37.8.2  nathanw 		 * Nothing to do here, really.
   1620  1.37.8.2  nathanw 		 */
   1621  1.37.8.2  nathanw 		return 0; /* XXX */
   1622  1.37.8.2  nathanw 
   1623  1.37.8.2  nathanw 	case DIOCEJECT:
   1624  1.37.8.2  nathanw 		if (*(int *)addr == 0) {
   1625  1.37.8.2  nathanw 			/*
   1626  1.37.8.2  nathanw 			 * Don't force eject: check that we are the only
   1627  1.37.8.2  nathanw 			 * partition open. If so, unlock it.
   1628  1.37.8.2  nathanw 			 */
   1629  1.37.8.2  nathanw 			if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 ||
   1630  1.37.8.2  nathanw 			    fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask !=
   1631  1.37.8.2  nathanw 			    fd->sc_dk.dk_openmask) {
   1632  1.37.8.2  nathanw 				return (EBUSY);
   1633  1.37.8.2  nathanw 			}
   1634  1.37.8.2  nathanw 		}
   1635  1.37.8.2  nathanw 		/* FALLTHROUGH */
   1636  1.37.8.2  nathanw 	case ODIOCEJECT:
   1637  1.37.8.2  nathanw 		fd_do_eject(fdc, unit);
   1638  1.37.8.2  nathanw 		return 0;
   1639  1.37.8.2  nathanw 
   1640  1.37.8.2  nathanw 	default:
   1641  1.37.8.2  nathanw 		return ENOTTY;
   1642  1.37.8.2  nathanw 	}
   1643  1.37.8.2  nathanw 
   1644  1.37.8.2  nathanw #ifdef DIAGNOSTIC
   1645  1.37.8.2  nathanw 	panic("fdioctl: impossible");
   1646  1.37.8.2  nathanw #endif
   1647  1.37.8.2  nathanw }
   1648  1.37.8.2  nathanw 
   1649  1.37.8.2  nathanw void
   1650  1.37.8.2  nathanw fd_do_eject(fdc, unit)
   1651  1.37.8.2  nathanw 	struct fdc_softc *fdc;
   1652  1.37.8.2  nathanw 	int unit;
   1653  1.37.8.2  nathanw {
   1654  1.37.8.2  nathanw 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
   1655  1.37.8.2  nathanw 			  0x20 | ( 1 << unit));
   1656  1.37.8.2  nathanw 	DELAY(1); /* XXX */
   1657  1.37.8.2  nathanw 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20);
   1658  1.37.8.2  nathanw }
   1659  1.37.8.2  nathanw 
   1660  1.37.8.2  nathanw /*
   1661  1.37.8.2  nathanw  * Build disk label. For now we only create a label from what we know
   1662  1.37.8.2  nathanw  * from 'sc'.
   1663  1.37.8.2  nathanw  */
   1664  1.37.8.2  nathanw static int
   1665  1.37.8.2  nathanw fdgetdisklabel(sc, dev)
   1666  1.37.8.2  nathanw 	struct fd_softc *sc;
   1667  1.37.8.2  nathanw 	dev_t dev;
   1668  1.37.8.2  nathanw {
   1669  1.37.8.2  nathanw 	struct disklabel *lp;
   1670  1.37.8.2  nathanw 	int part;
   1671  1.37.8.2  nathanw 
   1672  1.37.8.2  nathanw 	DPRINTF(("fdgetdisklabel()\n"));
   1673  1.37.8.2  nathanw 
   1674  1.37.8.2  nathanw 	part = DISKPART(dev);
   1675  1.37.8.2  nathanw 	lp = sc->sc_dk.dk_label;
   1676  1.37.8.2  nathanw 	memset(lp, 0, sizeof(struct disklabel));
   1677  1.37.8.2  nathanw 
   1678  1.37.8.2  nathanw 	lp->d_secsize     = 128 << sc->sc_type->secsize;
   1679  1.37.8.2  nathanw 	lp->d_ntracks     = sc->sc_type->heads;
   1680  1.37.8.2  nathanw 	lp->d_nsectors    = sc->sc_type->sectrac;
   1681  1.37.8.2  nathanw 	lp->d_secpercyl   = lp->d_ntracks * lp->d_nsectors;
   1682  1.37.8.2  nathanw 	lp->d_ncylinders  = sc->sc_type->size / lp->d_secpercyl;
   1683  1.37.8.2  nathanw 	lp->d_secperunit  = sc->sc_type->size;
   1684  1.37.8.2  nathanw 
   1685  1.37.8.2  nathanw 	lp->d_type        = DTYPE_FLOPPY;
   1686  1.37.8.2  nathanw 	lp->d_rpm         = 300; 	/* XXX */
   1687  1.37.8.2  nathanw 	lp->d_interleave  = 1;		/* FIXME: is this OK?		*/
   1688  1.37.8.2  nathanw 	lp->d_bbsize      = 0;
   1689  1.37.8.2  nathanw 	lp->d_sbsize      = 0;
   1690  1.37.8.2  nathanw 	lp->d_npartitions = part + 1;
   1691  1.37.8.2  nathanw #define STEP_DELAY	6000	/* 6ms (6000us) delay after stepping	*/
   1692  1.37.8.2  nathanw 	lp->d_trkseek     = STEP_DELAY; /* XXX */
   1693  1.37.8.2  nathanw 	lp->d_magic       = DISKMAGIC;
   1694  1.37.8.2  nathanw 	lp->d_magic2      = DISKMAGIC;
   1695  1.37.8.2  nathanw 	lp->d_checksum    = dkcksum(lp);
   1696  1.37.8.2  nathanw 	lp->d_partitions[part].p_size   = lp->d_secperunit;
   1697  1.37.8.2  nathanw 	lp->d_partitions[part].p_fstype = FS_UNUSED;
   1698  1.37.8.2  nathanw 	lp->d_partitions[part].p_fsize  = 1024;
   1699  1.37.8.2  nathanw 	lp->d_partitions[part].p_frag   = 8;
   1700  1.37.8.2  nathanw 
   1701  1.37.8.2  nathanw 	return(0);
   1702  1.37.8.2  nathanw }
   1703  1.37.8.2  nathanw 
   1704  1.37.8.2  nathanw #include <dev/cons.h>
   1705  1.37.8.2  nathanw 
   1706  1.37.8.2  nathanw /*
   1707  1.37.8.2  nathanw  * Mountroot hook: prompt the user to enter the root file system
   1708  1.37.8.2  nathanw  * floppy.
   1709  1.37.8.2  nathanw  */
   1710  1.37.8.2  nathanw void
   1711  1.37.8.2  nathanw fd_mountroot_hook(dev)
   1712  1.37.8.2  nathanw 	struct device *dev;
   1713  1.37.8.2  nathanw {
   1714  1.37.8.2  nathanw 	struct fd_softc *fd = (void*) dev;
   1715  1.37.8.2  nathanw 	struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
   1716  1.37.8.2  nathanw 	int c;
   1717  1.37.8.2  nathanw 
   1718  1.37.8.2  nathanw 	fd_do_eject(fdc, dev->dv_unit);
   1719  1.37.8.2  nathanw 	printf("Insert filesystem floppy and press return.");
   1720  1.37.8.2  nathanw 	for (;;) {
   1721  1.37.8.2  nathanw 		c = cngetc();
   1722  1.37.8.2  nathanw 		if ((c == '\r') || (c == '\n')) {
   1723  1.37.8.2  nathanw 			printf("\n");
   1724  1.37.8.2  nathanw 			break;
   1725  1.37.8.2  nathanw 		}
   1726  1.37.8.2  nathanw 	}
   1727  1.37.8.2  nathanw }
   1728