Home | History | Annotate | Line # | Download | only in dev
fd.c revision 1.37.8.5
      1  1.37.8.5  nathanw /*	$NetBSD: fd.c,v 1.37.8.5 2002/09/17 21:18: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.2  nathanw struct cfattach fdc_ca = {
    179  1.37.8.2  nathanw 	sizeof(struct fdc_softc), fdcprobe, fdcattach
    180  1.37.8.2  nathanw };
    181  1.37.8.2  nathanw 
    182  1.37.8.2  nathanw extern struct cfdriver fdc_cd;
    183  1.37.8.2  nathanw 
    184  1.37.8.2  nathanw /*
    185  1.37.8.2  nathanw  * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
    186  1.37.8.2  nathanw  * we tell them apart.
    187  1.37.8.2  nathanw  */
    188  1.37.8.2  nathanw struct fd_type {
    189  1.37.8.2  nathanw 	int	sectrac;	/* sectors per track */
    190  1.37.8.2  nathanw 	int	heads;		/* number of heads */
    191  1.37.8.2  nathanw 	int	seccyl;		/* sectors per cylinder */
    192  1.37.8.2  nathanw 	int	secsize;	/* size code for sectors */
    193  1.37.8.2  nathanw 	int	datalen;	/* data len when secsize = 0 */
    194  1.37.8.2  nathanw 	int	steprate;	/* step rate and head unload time */
    195  1.37.8.2  nathanw 	int	gap1;		/* gap len between sectors */
    196  1.37.8.2  nathanw 	int	gap2;		/* formatting gap */
    197  1.37.8.2  nathanw 	int	cyls;		/* total num of cylinders */
    198  1.37.8.2  nathanw 	int	size;		/* size of disk in sectors */
    199  1.37.8.2  nathanw 	int	step;		/* steps per cylinder */
    200  1.37.8.2  nathanw 	int	rate;		/* transfer speed code */
    201  1.37.8.2  nathanw 	char	*name;
    202  1.37.8.2  nathanw };
    203  1.37.8.2  nathanw 
    204  1.37.8.2  nathanw /* The order of entries in the following table is important -- BEWARE! */
    205  1.37.8.2  nathanw struct fd_type fd_types[] = {
    206  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 */
    207  1.37.8.2  nathanw         { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB"    }, /* 1.44MB diskette */
    208  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 */
    209  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 */
    210  1.37.8.2  nathanw         {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
    211  1.37.8.2  nathanw         {  9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB"    }, /* 3.5" 720kB diskette */
    212  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 */
    213  1.37.8.2  nathanw         {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x"  }, /* 360kB in 720kB drive */
    214  1.37.8.2  nathanw };
    215  1.37.8.2  nathanw 
    216  1.37.8.2  nathanw /* software state, per disk (with up to 4 disks per ctlr) */
    217  1.37.8.2  nathanw struct fd_softc {
    218  1.37.8.2  nathanw 	struct device sc_dev;
    219  1.37.8.2  nathanw 	struct disk sc_dk;
    220  1.37.8.2  nathanw 
    221  1.37.8.2  nathanw 	struct fd_type *sc_deftype;	/* default type descriptor */
    222  1.37.8.2  nathanw 	struct fd_type *sc_type;	/* current type descriptor */
    223  1.37.8.2  nathanw 
    224  1.37.8.2  nathanw 	struct callout sc_motoron_ch;
    225  1.37.8.2  nathanw 	struct callout sc_motoroff_ch;
    226  1.37.8.2  nathanw 
    227  1.37.8.2  nathanw 	daddr_t	sc_blkno;	/* starting block number */
    228  1.37.8.2  nathanw 	int sc_bcount;		/* byte count left */
    229  1.37.8.2  nathanw  	int sc_opts;			/* user-set options */
    230  1.37.8.2  nathanw 	int sc_skip;		/* bytes already transferred */
    231  1.37.8.2  nathanw 	int sc_nblks;		/* number of blocks currently transferring */
    232  1.37.8.2  nathanw 	int sc_nbytes;		/* number of bytes currently transferring */
    233  1.37.8.2  nathanw 
    234  1.37.8.2  nathanw 	int sc_drive;		/* physical unit number */
    235  1.37.8.2  nathanw 	int sc_flags;
    236  1.37.8.2  nathanw #define	FD_BOPEN	0x01		/* it's open */
    237  1.37.8.2  nathanw #define	FD_COPEN	0x02		/* it's open */
    238  1.37.8.2  nathanw #define	FD_OPEN		(FD_BOPEN|FD_COPEN)	/* it's open */
    239  1.37.8.2  nathanw #define	FD_MOTOR	0x04		/* motor should be on */
    240  1.37.8.2  nathanw #define	FD_MOTOR_WAIT	0x08		/* motor coming up */
    241  1.37.8.2  nathanw #define	FD_ALIVE	0x10		/* alive */
    242  1.37.8.2  nathanw 	int sc_cylin;		/* where we think the head is */
    243  1.37.8.2  nathanw 
    244  1.37.8.2  nathanw 	TAILQ_ENTRY(fd_softc) sc_drivechain;
    245  1.37.8.2  nathanw 	int sc_ops;		/* I/O ops since last switch */
    246  1.37.8.4  nathanw 	struct bufq_state sc_q;	/* pending I/O requests */
    247  1.37.8.2  nathanw 	int sc_active;		/* number of active I/O operations */
    248  1.37.8.2  nathanw 	u_char *sc_copybuf;	/* for secsize >=3 */
    249  1.37.8.2  nathanw 	u_char sc_part;		/* for secsize >=3 */
    250  1.37.8.2  nathanw #define	SEC_P10	0x02		/* first part */
    251  1.37.8.2  nathanw #define	SEC_P01	0x01		/* second part */
    252  1.37.8.2  nathanw #define	SEC_P11	0x03		/* both part */
    253  1.37.8.2  nathanw 
    254  1.37.8.2  nathanw #if NRND > 0
    255  1.37.8.2  nathanw 	rndsource_element_t	rnd_source;
    256  1.37.8.2  nathanw #endif
    257  1.37.8.2  nathanw };
    258  1.37.8.2  nathanw 
    259  1.37.8.2  nathanw /* floppy driver configuration */
    260  1.37.8.2  nathanw int fdprobe __P((struct device *, struct cfdata *, void *));
    261  1.37.8.2  nathanw void fdattach __P((struct device *, struct device *, void *));
    262  1.37.8.2  nathanw 
    263  1.37.8.2  nathanw struct cfattach fd_ca = {
    264  1.37.8.2  nathanw 	sizeof(struct fd_softc), fdprobe, fdattach
    265  1.37.8.2  nathanw };
    266  1.37.8.2  nathanw 
    267  1.37.8.2  nathanw extern struct cfdriver fd_cd;
    268  1.37.8.2  nathanw 
    269  1.37.8.5  nathanw dev_type_open(fdopen);
    270  1.37.8.5  nathanw dev_type_close(fdclose);
    271  1.37.8.5  nathanw dev_type_read(fdread);
    272  1.37.8.5  nathanw dev_type_write(fdwrite);
    273  1.37.8.5  nathanw dev_type_ioctl(fdioctl);
    274  1.37.8.5  nathanw dev_type_strategy(fdstrategy);
    275  1.37.8.5  nathanw 
    276  1.37.8.5  nathanw const struct bdevsw fd_bdevsw = {
    277  1.37.8.5  nathanw 	fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK
    278  1.37.8.5  nathanw };
    279  1.37.8.5  nathanw 
    280  1.37.8.5  nathanw const struct cdevsw fd_cdevsw = {
    281  1.37.8.5  nathanw 	fdopen, fdclose, fdread, fdwrite, fdioctl,
    282  1.37.8.5  nathanw 	nostop, notty, nopoll, nommap, D_DISK
    283  1.37.8.5  nathanw };
    284  1.37.8.5  nathanw 
    285  1.37.8.2  nathanw void fdstart __P((struct fd_softc *fd));
    286  1.37.8.2  nathanw 
    287  1.37.8.2  nathanw struct dkdriver fddkdriver = { fdstrategy };
    288  1.37.8.2  nathanw 
    289  1.37.8.2  nathanw void fd_set_motor __P((struct fdc_softc *fdc, int reset));
    290  1.37.8.2  nathanw void fd_motor_off __P((void *arg));
    291  1.37.8.2  nathanw void fd_motor_on __P((void *arg));
    292  1.37.8.2  nathanw int fdcresult __P((struct fdc_softc *fdc));
    293  1.37.8.2  nathanw int out_fdc __P((bus_space_tag_t, bus_space_handle_t, u_char x));
    294  1.37.8.2  nathanw void fdcstart __P((struct fdc_softc *fdc));
    295  1.37.8.2  nathanw void fdcstatus __P((struct device *dv, int n, char *s));
    296  1.37.8.2  nathanw void fdctimeout __P((void *arg));
    297  1.37.8.2  nathanw void fdcpseudointr __P((void *arg));
    298  1.37.8.2  nathanw void fdcretry __P((struct fdc_softc *fdc));
    299  1.37.8.2  nathanw void fdfinish __P((struct fd_softc *fd, struct buf *bp));
    300  1.37.8.2  nathanw __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
    301  1.37.8.2  nathanw static int fdcpoll __P((struct fdc_softc *));
    302  1.37.8.2  nathanw static int fdgetdisklabel __P((struct fd_softc *, dev_t));
    303  1.37.8.2  nathanw static void fd_do_eject __P((struct fdc_softc *, int));
    304  1.37.8.2  nathanw 
    305  1.37.8.2  nathanw void fd_mountroot_hook __P((struct device *));
    306  1.37.8.2  nathanw 
    307  1.37.8.2  nathanw /* dma transfer routines */
    308  1.37.8.2  nathanw __inline static void fdc_dmastart __P((struct fdc_softc*, int,
    309  1.37.8.2  nathanw 				       caddr_t, vsize_t));
    310  1.37.8.2  nathanw static int fdcdmaintr __P((void*));
    311  1.37.8.2  nathanw static int fdcdmaerrintr __P((void*));
    312  1.37.8.2  nathanw 
    313  1.37.8.2  nathanw __inline static void
    314  1.37.8.2  nathanw fdc_dmastart(fdc, read, addr, count)
    315  1.37.8.2  nathanw 	struct fdc_softc *fdc;
    316  1.37.8.2  nathanw 	int read;
    317  1.37.8.2  nathanw 	caddr_t addr;
    318  1.37.8.2  nathanw 	vsize_t count;
    319  1.37.8.2  nathanw {
    320  1.37.8.2  nathanw 	int error;
    321  1.37.8.2  nathanw 
    322  1.37.8.3  nathanw 	DPRINTF(("fdc_dmastart: (%s, addr = %p, count = %ld\n",
    323  1.37.8.2  nathanw 		 read ? "read" : "write", (caddr_t) addr, count));
    324  1.37.8.2  nathanw 
    325  1.37.8.2  nathanw 	error = bus_dmamap_load(fdc->sc_dmat, fdc->sc_dmamap, addr, count,
    326  1.37.8.2  nathanw 				0, BUS_DMA_NOWAIT);
    327  1.37.8.2  nathanw 	if (error) {
    328  1.37.8.2  nathanw 		panic ("fdc_dmastart: cannot load dmamap");
    329  1.37.8.2  nathanw 	}
    330  1.37.8.2  nathanw 
    331  1.37.8.2  nathanw 	bus_dmamap_sync(fdc->sc_dmat, fdc->sc_dmamap, 0, count,
    332  1.37.8.2  nathanw 			read?BUS_DMASYNC_PREREAD:BUS_DMASYNC_PREWRITE);
    333  1.37.8.2  nathanw 
    334  1.37.8.2  nathanw 	fdc->sc_xfer = dmac_prepare_xfer(fdc->sc_dmachan, fdc->sc_dmat,
    335  1.37.8.2  nathanw 					 fdc->sc_dmamap,
    336  1.37.8.2  nathanw 					 (read?
    337  1.37.8.2  nathanw 					  DMAC_OCR_DIR_DTM:DMAC_OCR_DIR_MTD),
    338  1.37.8.2  nathanw 					 (DMAC_SCR_MAC_COUNT_UP|
    339  1.37.8.2  nathanw 					  DMAC_SCR_DAC_NO_COUNT),
    340  1.37.8.2  nathanw 					 (u_int8_t*) (fdc->sc_addr +
    341  1.37.8.2  nathanw 						      fddata));	/* XXX */
    342  1.37.8.2  nathanw 
    343  1.37.8.2  nathanw 	dmac_start_xfer(fdc->sc_dmachan->ch_softc, fdc->sc_xfer);
    344  1.37.8.2  nathanw }
    345  1.37.8.2  nathanw 
    346  1.37.8.2  nathanw static int
    347  1.37.8.2  nathanw fdcdmaintr(arg)
    348  1.37.8.2  nathanw 	void *arg;
    349  1.37.8.2  nathanw {
    350  1.37.8.2  nathanw 	struct fdc_softc *fdc = arg;
    351  1.37.8.2  nathanw 
    352  1.37.8.2  nathanw 	bus_dmamap_unload(fdc->sc_dmat, fdc->sc_dmamap);
    353  1.37.8.2  nathanw 
    354  1.37.8.2  nathanw 	return 0;
    355  1.37.8.2  nathanw }
    356  1.37.8.2  nathanw 
    357  1.37.8.2  nathanw static int
    358  1.37.8.2  nathanw fdcdmaerrintr(dummy)
    359  1.37.8.2  nathanw 	void *dummy;
    360  1.37.8.2  nathanw {
    361  1.37.8.2  nathanw 	DPRINTF(("fdcdmaerrintr\n"));
    362  1.37.8.2  nathanw 
    363  1.37.8.2  nathanw 	return 0;
    364  1.37.8.2  nathanw }
    365  1.37.8.2  nathanw 
    366  1.37.8.2  nathanw /* ARGSUSED */
    367  1.37.8.2  nathanw int
    368  1.37.8.2  nathanw fdcprobe(parent, cf, aux)
    369  1.37.8.2  nathanw 	struct device *parent;
    370  1.37.8.2  nathanw 	struct cfdata *cf;
    371  1.37.8.2  nathanw 	void *aux;
    372  1.37.8.2  nathanw {
    373  1.37.8.2  nathanw 	struct intio_attach_args *ia = aux;
    374  1.37.8.2  nathanw 
    375  1.37.8.2  nathanw 	if (strcmp(ia->ia_name, "fdc") != 0)
    376  1.37.8.2  nathanw 		return 0;
    377  1.37.8.2  nathanw 
    378  1.37.8.2  nathanw 	if (ia->ia_addr == INTIOCF_ADDR_DEFAULT)
    379  1.37.8.2  nathanw 		ia->ia_addr = FDC_ADDR;
    380  1.37.8.2  nathanw 	if (ia->ia_intr == INTIOCF_INTR_DEFAULT)
    381  1.37.8.2  nathanw 		ia->ia_intr = FDC_INTR;
    382  1.37.8.2  nathanw 	if (ia->ia_dma == INTIOCF_DMA_DEFAULT)
    383  1.37.8.2  nathanw 		ia->ia_dma = FDC_DMA;
    384  1.37.8.2  nathanw 	if (ia->ia_dmaintr == INTIOCF_DMAINTR_DEFAULT)
    385  1.37.8.2  nathanw 		ia->ia_dmaintr = FDC_DMAINTR;
    386  1.37.8.2  nathanw 
    387  1.37.8.2  nathanw 	if ((ia->ia_intr & 0x03) != 0)
    388  1.37.8.2  nathanw 		return 0;
    389  1.37.8.2  nathanw 
    390  1.37.8.2  nathanw 	ia->ia_size = 0x2000;
    391  1.37.8.2  nathanw 	if (intio_map_allocate_region (parent, ia, INTIO_MAP_TESTONLY))
    392  1.37.8.2  nathanw 		return 0;
    393  1.37.8.2  nathanw 
    394  1.37.8.2  nathanw 	/* builtin device; always there */
    395  1.37.8.2  nathanw 	return 1;
    396  1.37.8.2  nathanw }
    397  1.37.8.2  nathanw 
    398  1.37.8.2  nathanw /*
    399  1.37.8.2  nathanw  * Arguments passed between fdcattach and fdprobe.
    400  1.37.8.2  nathanw  */
    401  1.37.8.2  nathanw struct fdc_attach_args {
    402  1.37.8.2  nathanw 	int fa_drive;
    403  1.37.8.2  nathanw 	struct fd_type *fa_deftype;
    404  1.37.8.2  nathanw };
    405  1.37.8.2  nathanw 
    406  1.37.8.2  nathanw /*
    407  1.37.8.2  nathanw  * Print the location of a disk drive (called just before attaching the
    408  1.37.8.2  nathanw  * the drive).  If `fdc' is not NULL, the drive was found but was not
    409  1.37.8.2  nathanw  * in the system config file; print the drive name as well.
    410  1.37.8.2  nathanw  * Return QUIET (config_find ignores this if the device was configured) to
    411  1.37.8.2  nathanw  * avoid printing `fdN not configured' messages.
    412  1.37.8.2  nathanw  */
    413  1.37.8.2  nathanw int
    414  1.37.8.2  nathanw fdprint(aux, fdc)
    415  1.37.8.2  nathanw 	void *aux;
    416  1.37.8.2  nathanw 	const char *fdc;
    417  1.37.8.2  nathanw {
    418  1.37.8.2  nathanw 	register struct fdc_attach_args *fa = aux;
    419  1.37.8.2  nathanw 
    420  1.37.8.2  nathanw 	if (!fdc)
    421  1.37.8.2  nathanw 		printf(" drive %d", fa->fa_drive);
    422  1.37.8.2  nathanw 	return QUIET;
    423  1.37.8.2  nathanw }
    424  1.37.8.2  nathanw 
    425  1.37.8.2  nathanw void
    426  1.37.8.2  nathanw fdcattach(parent, self, aux)
    427  1.37.8.2  nathanw 	struct device *parent, *self;
    428  1.37.8.2  nathanw 	void *aux;
    429  1.37.8.2  nathanw {
    430  1.37.8.2  nathanw 	struct fdc_softc *fdc = (void *)self;
    431  1.37.8.2  nathanw 	bus_space_tag_t iot;
    432  1.37.8.2  nathanw 	bus_space_handle_t ioh;
    433  1.37.8.2  nathanw 	struct intio_attach_args *ia = aux;
    434  1.37.8.2  nathanw 	struct fdc_attach_args fa;
    435  1.37.8.2  nathanw 
    436  1.37.8.2  nathanw 	iot = ia->ia_bst;
    437  1.37.8.2  nathanw 
    438  1.37.8.2  nathanw 	printf("\n");
    439  1.37.8.2  nathanw 
    440  1.37.8.2  nathanw 	callout_init(&fdc->sc_timo_ch);
    441  1.37.8.2  nathanw 	callout_init(&fdc->sc_intr_ch);
    442  1.37.8.2  nathanw 
    443  1.37.8.2  nathanw 	/* Re-map the I/O space. */
    444  1.37.8.2  nathanw 	bus_space_map(iot, ia->ia_addr, 0x2000, BUS_SPACE_MAP_SHIFTED, &ioh);
    445  1.37.8.2  nathanw 
    446  1.37.8.2  nathanw 	fdc->sc_iot = iot;
    447  1.37.8.2  nathanw 	fdc->sc_ioh = ioh;
    448  1.37.8.2  nathanw 	fdc->sc_addr = (void*) ia->ia_addr;
    449  1.37.8.2  nathanw 
    450  1.37.8.2  nathanw 	fdc->sc_dmat = ia->ia_dmat;
    451  1.37.8.2  nathanw 	fdc->sc_state = DEVIDLE;
    452  1.37.8.2  nathanw 	TAILQ_INIT(&fdc->sc_drives);
    453  1.37.8.2  nathanw 
    454  1.37.8.2  nathanw 	/* Initialize DMAC channel */
    455  1.37.8.2  nathanw 	fdc->sc_dmachan = dmac_alloc_channel(parent, ia->ia_dma, "fdc",
    456  1.37.8.2  nathanw 					     ia->ia_dmaintr, fdcdmaintr, fdc,
    457  1.37.8.2  nathanw 					     ia->ia_dmaintr+1, fdcdmaerrintr,
    458  1.37.8.2  nathanw 					     fdc);
    459  1.37.8.2  nathanw 	if (bus_dmamap_create(fdc->sc_dmat, FDC_MAXIOSIZE, 1, DMAC_MAXSEGSZ,
    460  1.37.8.2  nathanw 			      0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
    461  1.37.8.2  nathanw 			      &fdc->sc_dmamap)) {
    462  1.37.8.2  nathanw 		printf("%s: can't set up intio DMA map\n",
    463  1.37.8.2  nathanw 		    fdc->sc_dev.dv_xname);
    464  1.37.8.2  nathanw 		return;
    465  1.37.8.2  nathanw 	}
    466  1.37.8.2  nathanw 
    467  1.37.8.2  nathanw 	if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc))
    468  1.37.8.2  nathanw 		panic ("Could not establish interrupt (duplicated vector?).");
    469  1.37.8.2  nathanw 	intio_set_ivec(ia->ia_intr);
    470  1.37.8.2  nathanw 
    471  1.37.8.2  nathanw 	/* reset */
    472  1.37.8.2  nathanw 	intio_disable_intr(SICILIAN_INTR_FDD);
    473  1.37.8.2  nathanw 	intio_enable_intr(SICILIAN_INTR_FDC);
    474  1.37.8.2  nathanw 	fdcresult(fdc);
    475  1.37.8.2  nathanw 	fdcreset(fdc);
    476  1.37.8.2  nathanw 
    477  1.37.8.2  nathanw 	printf("%s: uPD72065 FDC\n", fdc->sc_dev.dv_xname);
    478  1.37.8.2  nathanw 	out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
    479  1.37.8.2  nathanw 	out_fdc(iot, ioh, 0xd0);
    480  1.37.8.2  nathanw 	out_fdc(iot, ioh, 0x10);
    481  1.37.8.2  nathanw 
    482  1.37.8.2  nathanw 	/* physical limit: four drives per controller. */
    483  1.37.8.2  nathanw 	for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
    484  1.37.8.2  nathanw 		(void)config_found(self, (void *)&fa, fdprint);
    485  1.37.8.2  nathanw 	}
    486  1.37.8.2  nathanw 
    487  1.37.8.2  nathanw 	intio_enable_intr(SICILIAN_INTR_FDC);
    488  1.37.8.2  nathanw }
    489  1.37.8.2  nathanw 
    490  1.37.8.2  nathanw void
    491  1.37.8.2  nathanw fdcreset(fdc)
    492  1.37.8.2  nathanw 	struct fdc_softc *fdc;
    493  1.37.8.2  nathanw {
    494  1.37.8.2  nathanw 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdsts, NE7CMD_RESET);
    495  1.37.8.2  nathanw }
    496  1.37.8.2  nathanw 
    497  1.37.8.2  nathanw static int
    498  1.37.8.2  nathanw fdcpoll(fdc)
    499  1.37.8.2  nathanw 	struct fdc_softc *fdc;
    500  1.37.8.2  nathanw {
    501  1.37.8.2  nathanw 	int i = 25000, n;
    502  1.37.8.2  nathanw 	while (--i > 0) {
    503  1.37.8.2  nathanw 		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
    504  1.37.8.2  nathanw 			out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
    505  1.37.8.2  nathanw 			n = fdcresult(fdc);
    506  1.37.8.2  nathanw 			break;
    507  1.37.8.2  nathanw 		}
    508  1.37.8.2  nathanw 		DELAY(100);
    509  1.37.8.2  nathanw 	}
    510  1.37.8.2  nathanw 	return i;
    511  1.37.8.2  nathanw }
    512  1.37.8.2  nathanw 
    513  1.37.8.2  nathanw int
    514  1.37.8.2  nathanw fdprobe(parent, cf, aux)
    515  1.37.8.2  nathanw 	struct device *parent;
    516  1.37.8.2  nathanw 	struct cfdata *cf;
    517  1.37.8.2  nathanw 	void *aux;
    518  1.37.8.2  nathanw {
    519  1.37.8.2  nathanw 	struct fdc_softc *fdc = (void *)parent;
    520  1.37.8.2  nathanw 	struct fd_type *type;
    521  1.37.8.2  nathanw 	struct fdc_attach_args *fa = aux;
    522  1.37.8.2  nathanw 	int drive = fa->fa_drive;
    523  1.37.8.2  nathanw 	bus_space_tag_t iot = fdc->sc_iot;
    524  1.37.8.2  nathanw 	bus_space_handle_t ioh = fdc->sc_ioh;
    525  1.37.8.2  nathanw 	int n;
    526  1.37.8.2  nathanw 	int found = 0;
    527  1.37.8.2  nathanw 	int i;
    528  1.37.8.2  nathanw 
    529  1.37.8.2  nathanw 	if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
    530  1.37.8.2  nathanw 	    cf->cf_loc[FDCCF_UNIT] != drive)
    531  1.37.8.2  nathanw 		return 0;
    532  1.37.8.2  nathanw 
    533  1.37.8.2  nathanw 	type = &fd_types[0];	/* XXX 1.2MB */
    534  1.37.8.2  nathanw 
    535  1.37.8.2  nathanw 	intio_disable_intr(SICILIAN_INTR_FDC);
    536  1.37.8.2  nathanw 
    537  1.37.8.2  nathanw 	/* select drive and turn on motor */
    538  1.37.8.2  nathanw 	bus_space_write_1(iot, ioh, fdctl, 0x80 | (type->rate << 4)| drive);
    539  1.37.8.2  nathanw 	fdc_force_ready(FDCRDY);
    540  1.37.8.2  nathanw 	fdcpoll(fdc);
    541  1.37.8.2  nathanw 
    542  1.37.8.2  nathanw retry:
    543  1.37.8.2  nathanw 	out_fdc(iot, ioh, NE7CMD_RECAL);
    544  1.37.8.2  nathanw 	out_fdc(iot, ioh, drive);
    545  1.37.8.2  nathanw 
    546  1.37.8.2  nathanw 	i = 25000;
    547  1.37.8.2  nathanw 	while (--i > 0) {
    548  1.37.8.2  nathanw 		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
    549  1.37.8.2  nathanw 			out_fdc(iot, ioh, NE7CMD_SENSEI);
    550  1.37.8.2  nathanw 			n = fdcresult(fdc);
    551  1.37.8.2  nathanw 			break;
    552  1.37.8.2  nathanw 		}
    553  1.37.8.2  nathanw 		DELAY(100);
    554  1.37.8.2  nathanw 	}
    555  1.37.8.2  nathanw 
    556  1.37.8.2  nathanw #ifdef FDDEBUG
    557  1.37.8.2  nathanw 	{
    558  1.37.8.2  nathanw 		int i;
    559  1.37.8.2  nathanw 		DPRINTF(("fdprobe: status"));
    560  1.37.8.2  nathanw 		for (i = 0; i < n; i++)
    561  1.37.8.2  nathanw 			DPRINTF((" %x", fdc->sc_status[i]));
    562  1.37.8.2  nathanw 		DPRINTF(("\n"));
    563  1.37.8.2  nathanw 	}
    564  1.37.8.2  nathanw #endif
    565  1.37.8.2  nathanw 
    566  1.37.8.2  nathanw 	if (n == 2) {
    567  1.37.8.2  nathanw 		if ((fdc->sc_status[0] & 0xf0) == 0x20) {
    568  1.37.8.2  nathanw 			found = 1;
    569  1.37.8.2  nathanw 		} else if ((fdc->sc_status[0] & 0xf0) == 0xc0) {
    570  1.37.8.2  nathanw 			goto retry;
    571  1.37.8.2  nathanw 		}
    572  1.37.8.2  nathanw 	}
    573  1.37.8.2  nathanw 
    574  1.37.8.2  nathanw 	/* turn off motor */
    575  1.37.8.2  nathanw 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh,
    576  1.37.8.2  nathanw 			  fdctl, (type->rate << 4)| drive);
    577  1.37.8.2  nathanw 	fdc_force_ready(FDCSTBY);
    578  1.37.8.2  nathanw 	if (!found) {
    579  1.37.8.2  nathanw 		intio_enable_intr(SICILIAN_INTR_FDC);
    580  1.37.8.2  nathanw 		return 0;
    581  1.37.8.2  nathanw 	}
    582  1.37.8.2  nathanw 
    583  1.37.8.2  nathanw 	return 1;
    584  1.37.8.2  nathanw }
    585  1.37.8.2  nathanw 
    586  1.37.8.2  nathanw /*
    587  1.37.8.2  nathanw  * Controller is working, and drive responded.  Attach it.
    588  1.37.8.2  nathanw  */
    589  1.37.8.2  nathanw void
    590  1.37.8.2  nathanw fdattach(parent, self, aux)
    591  1.37.8.2  nathanw 	struct device *parent, *self;
    592  1.37.8.2  nathanw 	void *aux;
    593  1.37.8.2  nathanw {
    594  1.37.8.2  nathanw 	struct fdc_softc *fdc = (void *)parent;
    595  1.37.8.2  nathanw 	struct fd_softc *fd = (void *)self;
    596  1.37.8.2  nathanw 	struct fdc_attach_args *fa = aux;
    597  1.37.8.2  nathanw 	struct fd_type *type = &fd_types[0];	/* XXX 1.2MB */
    598  1.37.8.2  nathanw 	int drive = fa->fa_drive;
    599  1.37.8.2  nathanw 
    600  1.37.8.2  nathanw 	callout_init(&fd->sc_motoron_ch);
    601  1.37.8.2  nathanw 	callout_init(&fd->sc_motoroff_ch);
    602  1.37.8.2  nathanw 
    603  1.37.8.2  nathanw 	fd->sc_flags = 0;
    604  1.37.8.2  nathanw 
    605  1.37.8.2  nathanw 	if (type)
    606  1.37.8.2  nathanw 		printf(": %s, %d cyl, %d head, %d sec\n", type->name,
    607  1.37.8.2  nathanw 		       type->cyls, type->heads, type->sectrac);
    608  1.37.8.2  nathanw 	else
    609  1.37.8.2  nathanw 		printf(": density unknown\n");
    610  1.37.8.2  nathanw 
    611  1.37.8.4  nathanw 	bufq_alloc(&fd->sc_q, BUFQ_DISKSORT|BUFQ_SORT_CYLINDER);
    612  1.37.8.2  nathanw 	fd->sc_cylin = -1;
    613  1.37.8.2  nathanw 	fd->sc_drive = drive;
    614  1.37.8.2  nathanw 	fd->sc_deftype = type;
    615  1.37.8.2  nathanw 	fdc->sc_fd[drive] = fd;
    616  1.37.8.2  nathanw 
    617  1.37.8.2  nathanw 	fd->sc_copybuf = (u_char *)malloc(NBPG, M_DEVBUF, M_WAITOK);
    618  1.37.8.2  nathanw 	if (fd->sc_copybuf == 0)
    619  1.37.8.2  nathanw 		printf("fdprobe: WARNING!! malloc() failed.\n");
    620  1.37.8.2  nathanw 	fd->sc_flags |= FD_ALIVE;
    621  1.37.8.2  nathanw 
    622  1.37.8.2  nathanw 	/*
    623  1.37.8.2  nathanw 	 * Initialize and attach the disk structure.
    624  1.37.8.2  nathanw 	 */
    625  1.37.8.2  nathanw 	fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
    626  1.37.8.2  nathanw 	fd->sc_dk.dk_driver = &fddkdriver;
    627  1.37.8.2  nathanw 	disk_attach(&fd->sc_dk);
    628  1.37.8.2  nathanw 
    629  1.37.8.2  nathanw 	/*
    630  1.37.8.2  nathanw 	 * Establish a mountroot_hook anyway in case we booted
    631  1.37.8.2  nathanw 	 * with RB_ASKNAME and get selected as the boot device.
    632  1.37.8.2  nathanw 	 */
    633  1.37.8.2  nathanw 	mountroothook_establish(fd_mountroot_hook, &fd->sc_dev);
    634  1.37.8.2  nathanw 
    635  1.37.8.2  nathanw #if NRND > 0
    636  1.37.8.2  nathanw 	rnd_attach_source(&fd->rnd_source, fd->sc_dev.dv_xname,
    637  1.37.8.2  nathanw 			  RND_TYPE_DISK, 0);
    638  1.37.8.2  nathanw #endif
    639  1.37.8.2  nathanw }
    640  1.37.8.2  nathanw 
    641  1.37.8.2  nathanw __inline struct fd_type *
    642  1.37.8.2  nathanw fd_dev_to_type(fd, dev)
    643  1.37.8.2  nathanw 	struct fd_softc *fd;
    644  1.37.8.2  nathanw 	dev_t dev;
    645  1.37.8.2  nathanw {
    646  1.37.8.2  nathanw 	int type = FDTYPE(dev);
    647  1.37.8.2  nathanw 
    648  1.37.8.2  nathanw 	if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
    649  1.37.8.2  nathanw 		return NULL;
    650  1.37.8.2  nathanw 	return &fd_types[type];
    651  1.37.8.2  nathanw }
    652  1.37.8.2  nathanw 
    653  1.37.8.2  nathanw void
    654  1.37.8.2  nathanw fdstrategy(bp)
    655  1.37.8.2  nathanw 	register struct buf *bp;	/* IO operation to perform */
    656  1.37.8.2  nathanw {
    657  1.37.8.2  nathanw 	struct fd_softc *fd;
    658  1.37.8.2  nathanw 	int unit = FDUNIT(bp->b_dev);
    659  1.37.8.2  nathanw 	int sz;
    660  1.37.8.2  nathanw  	int s;
    661  1.37.8.2  nathanw 
    662  1.37.8.2  nathanw 	if (unit >= fd_cd.cd_ndevs ||
    663  1.37.8.2  nathanw 	    (fd = fd_cd.cd_devs[unit]) == 0 ||
    664  1.37.8.2  nathanw 	    bp->b_blkno < 0 ||
    665  1.37.8.2  nathanw 	    (bp->b_bcount % FDC_BSIZE) != 0) {
    666  1.37.8.3  nathanw 		DPRINTF(("fdstrategy: unit=%d, blkno=%d, bcount=%ld\n", unit,
    667  1.37.8.2  nathanw 			 bp->b_blkno, bp->b_bcount));
    668  1.37.8.2  nathanw 		bp->b_error = EINVAL;
    669  1.37.8.2  nathanw 		goto bad;
    670  1.37.8.2  nathanw 	}
    671  1.37.8.2  nathanw 
    672  1.37.8.2  nathanw 	/* If it's a null transfer, return immediately. */
    673  1.37.8.2  nathanw 	if (bp->b_bcount == 0)
    674  1.37.8.2  nathanw 		goto done;
    675  1.37.8.2  nathanw 
    676  1.37.8.2  nathanw 	sz = howmany(bp->b_bcount, FDC_BSIZE);
    677  1.37.8.2  nathanw 
    678  1.37.8.2  nathanw 	if (bp->b_blkno + sz > (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
    679  1.37.8.2  nathanw 		sz = (fd->sc_type->size << (fd->sc_type->secsize - 2)) - 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.2  nathanw 					ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
   1134  1.37.8.2  nathanw 					break;
   1135  1.37.8.2  nathanw 				}
   1136  1.37.8.2  nathanw 			}
   1137  1.37.8.2  nathanw 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
   1138  1.37.8.2  nathanw 			fd_set_motor(fdc, 0);
   1139  1.37.8.2  nathanw 			fdc->sc_state = MOTORWAIT;
   1140  1.37.8.2  nathanw 			/* allow .5s for motor to stabilize */
   1141  1.37.8.2  nathanw 			callout_reset(&fd->sc_motoron_ch, hz / 2,
   1142  1.37.8.2  nathanw 			    fd_motor_on, fd);
   1143  1.37.8.2  nathanw 			return 1;
   1144  1.37.8.2  nathanw 		}
   1145  1.37.8.2  nathanw 		/* Make sure the right drive is selected. */
   1146  1.37.8.2  nathanw 		fd_set_motor(fdc, 0);
   1147  1.37.8.2  nathanw 
   1148  1.37.8.2  nathanw 		/* fall through */
   1149  1.37.8.2  nathanw 	case DOSEEK:
   1150  1.37.8.2  nathanw 	doseek:
   1151  1.37.8.2  nathanw 		DPRINTF(("fdcintr: in DOSEEK\n"));
   1152  1.37.8.2  nathanw 		if (fd->sc_cylin == bp->b_cylinder)
   1153  1.37.8.2  nathanw 			goto doio;
   1154  1.37.8.2  nathanw 
   1155  1.37.8.2  nathanw 		out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
   1156  1.37.8.2  nathanw 		out_fdc(iot, ioh, 0xd0);	/* XXX const */
   1157  1.37.8.2  nathanw 		out_fdc(iot, ioh, 0x10);
   1158  1.37.8.2  nathanw 
   1159  1.37.8.2  nathanw 		out_fdc(iot, ioh, NE7CMD_SEEK);	/* seek function */
   1160  1.37.8.2  nathanw 		out_fdc(iot, ioh, fd->sc_drive);	/* drive number */
   1161  1.37.8.2  nathanw 		out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
   1162  1.37.8.2  nathanw 
   1163  1.37.8.2  nathanw 		fd->sc_cylin = -1;
   1164  1.37.8.2  nathanw 		fdc->sc_state = SEEKWAIT;
   1165  1.37.8.2  nathanw 
   1166  1.37.8.2  nathanw 		fd->sc_dk.dk_seek++;
   1167  1.37.8.2  nathanw 		disk_busy(&fd->sc_dk);
   1168  1.37.8.2  nathanw 
   1169  1.37.8.2  nathanw 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
   1170  1.37.8.2  nathanw 		return 1;
   1171  1.37.8.2  nathanw 
   1172  1.37.8.2  nathanw 	case DOIO:
   1173  1.37.8.2  nathanw 	doio:
   1174  1.37.8.2  nathanw 		DPRINTF(("fdcintr: DOIO: "));
   1175  1.37.8.2  nathanw 		type = fd->sc_type;
   1176  1.37.8.2  nathanw 		sectrac = type->sectrac;
   1177  1.37.8.2  nathanw 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
   1178  1.37.8.2  nathanw 		sec = pos / (1 << (type->secsize - 2));
   1179  1.37.8.2  nathanw 		if (type->secsize == 2) {
   1180  1.37.8.2  nathanw 			fd->sc_part = SEC_P11;
   1181  1.37.8.2  nathanw 			nblks = (sectrac - sec) << (type->secsize - 2);
   1182  1.37.8.2  nathanw 			nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
   1183  1.37.8.2  nathanw 			DPRINTF(("nblks(0)"));
   1184  1.37.8.2  nathanw 		} else if ((fd->sc_blkno % 2) == 0) {
   1185  1.37.8.2  nathanw 			if (fd->sc_bcount & 0x00000200) {
   1186  1.37.8.2  nathanw 				if (fd->sc_bcount == FDC_BSIZE) {
   1187  1.37.8.2  nathanw 					fd->sc_part = SEC_P10;
   1188  1.37.8.2  nathanw 					nblks = 1;
   1189  1.37.8.2  nathanw 					DPRINTF(("nblks(1)"));
   1190  1.37.8.2  nathanw 				} else {
   1191  1.37.8.2  nathanw 					fd->sc_part = SEC_P11;
   1192  1.37.8.2  nathanw 					nblks = (sectrac - sec) * 2;
   1193  1.37.8.2  nathanw 					nblks = min(nblks, fd->sc_bcount
   1194  1.37.8.2  nathanw 						    / FDC_BSIZE - 1);
   1195  1.37.8.2  nathanw 					DPRINTF(("nblks(2)"));
   1196  1.37.8.2  nathanw 				}
   1197  1.37.8.2  nathanw 			} else {
   1198  1.37.8.2  nathanw 				fd->sc_part = SEC_P11;
   1199  1.37.8.2  nathanw 				nblks = (sectrac - sec)
   1200  1.37.8.2  nathanw 					<< (type->secsize - 2);
   1201  1.37.8.2  nathanw 				nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
   1202  1.37.8.2  nathanw 				DPRINTF(("nblks(3)"));
   1203  1.37.8.2  nathanw 			}
   1204  1.37.8.2  nathanw 		} else {
   1205  1.37.8.2  nathanw 			fd->sc_part = SEC_P01;
   1206  1.37.8.2  nathanw 			nblks = 1;
   1207  1.37.8.2  nathanw 			DPRINTF(("nblks(4)"));
   1208  1.37.8.2  nathanw 		}
   1209  1.37.8.2  nathanw 		nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
   1210  1.37.8.2  nathanw 		DPRINTF((" %d\n", nblks));
   1211  1.37.8.2  nathanw 		fd->sc_nblks = nblks;
   1212  1.37.8.2  nathanw 		fd->sc_nbytes = nblks * FDC_BSIZE;
   1213  1.37.8.2  nathanw 		head = (fd->sc_blkno
   1214  1.37.8.2  nathanw 			% (type->seccyl * (1 << (type->secsize - 2))))
   1215  1.37.8.2  nathanw 			 / (type->sectrac * (1 << (type->secsize - 2)));
   1216  1.37.8.2  nathanw 
   1217  1.37.8.2  nathanw #ifdef DIAGNOSTIC
   1218  1.37.8.2  nathanw 		{int block;
   1219  1.37.8.2  nathanw 		 block = ((fd->sc_cylin * type->heads + head) * type->sectrac
   1220  1.37.8.2  nathanw 			  + sec) * (1 << (type->secsize - 2));
   1221  1.37.8.2  nathanw 		 block += (fd->sc_part == SEC_P01) ? 1 : 0;
   1222  1.37.8.2  nathanw 		 if (block != fd->sc_blkno) {
   1223  1.37.8.2  nathanw 			 printf("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec, type->secsize);
   1224  1.37.8.2  nathanw 			 printf("fdcintr: doio: block %d != blkno %d\n", block, fd->sc_blkno);
   1225  1.37.8.2  nathanw #ifdef DDB
   1226  1.37.8.2  nathanw 			 Debugger();
   1227  1.37.8.2  nathanw #endif
   1228  1.37.8.2  nathanw 		 }}
   1229  1.37.8.2  nathanw #endif
   1230  1.37.8.2  nathanw 		read = bp->b_flags & B_READ;
   1231  1.37.8.2  nathanw 		DPRINTF(("fdcintr: %s drive %d track %d head %d sec %d nblks %d, skip %d\n",
   1232  1.37.8.2  nathanw 			 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
   1233  1.37.8.2  nathanw 			 head, sec, nblks, fd->sc_skip));
   1234  1.37.8.2  nathanw 		DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
   1235  1.37.8.2  nathanw 			 type->secsize));
   1236  1.37.8.2  nathanw 
   1237  1.37.8.2  nathanw 		if (fd->sc_part != SEC_P11)
   1238  1.37.8.2  nathanw 			goto docopy;
   1239  1.37.8.2  nathanw 
   1240  1.37.8.2  nathanw 		fdc_dmastart(fdc,
   1241  1.37.8.2  nathanw 			     read, bp->b_data + fd->sc_skip, fd->sc_nbytes);
   1242  1.37.8.2  nathanw 		if (read)
   1243  1.37.8.2  nathanw 			out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
   1244  1.37.8.2  nathanw 		else
   1245  1.37.8.2  nathanw 			out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
   1246  1.37.8.2  nathanw 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1247  1.37.8.2  nathanw 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
   1248  1.37.8.2  nathanw 		out_fdc(iot, ioh, head);
   1249  1.37.8.2  nathanw 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
   1250  1.37.8.2  nathanw 		out_fdc(iot, ioh, type->secsize);	/* sector size */
   1251  1.37.8.2  nathanw 		out_fdc(iot, ioh, type->sectrac);	/* sectors/track */
   1252  1.37.8.2  nathanw 		out_fdc(iot, ioh, type->gap1);		/* gap1 size */
   1253  1.37.8.2  nathanw 		out_fdc(iot, ioh, type->datalen);	/* data length */
   1254  1.37.8.2  nathanw 		fdc->sc_state = IOCOMPLETE;
   1255  1.37.8.2  nathanw 
   1256  1.37.8.2  nathanw 		disk_busy(&fd->sc_dk);
   1257  1.37.8.2  nathanw 
   1258  1.37.8.2  nathanw 		/* allow 2 seconds for operation */
   1259  1.37.8.2  nathanw 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1260  1.37.8.2  nathanw 		return 1;				/* will return later */
   1261  1.37.8.2  nathanw 
   1262  1.37.8.2  nathanw 	case DOCOPY:
   1263  1.37.8.2  nathanw 	docopy:
   1264  1.37.8.2  nathanw 		DPRINTF(("fdcintr: DOCOPY:\n"));
   1265  1.37.8.2  nathanw 		fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024);
   1266  1.37.8.2  nathanw 		out_fdc(iot, ioh, NE7CMD_READ);		/* READ */
   1267  1.37.8.2  nathanw 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1268  1.37.8.2  nathanw 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
   1269  1.37.8.2  nathanw 		out_fdc(iot, ioh, head);
   1270  1.37.8.2  nathanw 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
   1271  1.37.8.2  nathanw 		out_fdc(iot, ioh, type->secsize);	/* sector size */
   1272  1.37.8.2  nathanw 		out_fdc(iot, ioh, type->sectrac);	/* sectors/track */
   1273  1.37.8.2  nathanw 		out_fdc(iot, ioh, type->gap1);		/* gap1 size */
   1274  1.37.8.2  nathanw 		out_fdc(iot, ioh, type->datalen);	/* data length */
   1275  1.37.8.2  nathanw 		fdc->sc_state = COPYCOMPLETE;
   1276  1.37.8.2  nathanw 		/* allow 2 seconds for operation */
   1277  1.37.8.2  nathanw 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1278  1.37.8.2  nathanw 		return 1;				/* will return later */
   1279  1.37.8.2  nathanw 
   1280  1.37.8.2  nathanw 	case DOIOHALF:
   1281  1.37.8.2  nathanw 	doiohalf:
   1282  1.37.8.2  nathanw 		DPRINTF((" DOIOHALF:\n"));
   1283  1.37.8.2  nathanw 
   1284  1.37.8.2  nathanw #ifdef DIAGNOSTIC
   1285  1.37.8.2  nathanw 		type = fd->sc_type;
   1286  1.37.8.2  nathanw 		sectrac = type->sectrac;
   1287  1.37.8.2  nathanw 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
   1288  1.37.8.2  nathanw 		sec = pos / (1 << (type->secsize - 2));
   1289  1.37.8.2  nathanw 		head = (fd->sc_blkno
   1290  1.37.8.2  nathanw 			% (type->seccyl * (1 << (type->secsize - 2))))
   1291  1.37.8.2  nathanw 			 / (type->sectrac * (1 << (type->secsize - 2)));
   1292  1.37.8.2  nathanw 		{int block;
   1293  1.37.8.2  nathanw 		 block = ((fd->sc_cylin * type->heads + head) * type->sectrac + sec)
   1294  1.37.8.2  nathanw 			 * (1 << (type->secsize - 2));
   1295  1.37.8.2  nathanw 		 block += (fd->sc_part == SEC_P01) ? 1 : 0;
   1296  1.37.8.2  nathanw 		 if (block != fd->sc_blkno) {
   1297  1.37.8.2  nathanw 			 printf("fdcintr: block %d != blkno %d\n", block, fd->sc_blkno);
   1298  1.37.8.2  nathanw #ifdef DDB
   1299  1.37.8.2  nathanw 			 Debugger();
   1300  1.37.8.2  nathanw #endif
   1301  1.37.8.2  nathanw 		 }}
   1302  1.37.8.2  nathanw #endif
   1303  1.37.8.2  nathanw 		if ((read = bp->b_flags & B_READ)) {
   1304  1.37.8.2  nathanw 			memcpy(bp->b_data + fd->sc_skip, fd->sc_copybuf
   1305  1.37.8.2  nathanw 			    + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
   1306  1.37.8.2  nathanw 			    FDC_BSIZE);
   1307  1.37.8.2  nathanw 			fdc->sc_state = IOCOMPLETE;
   1308  1.37.8.2  nathanw 			goto iocomplete2;
   1309  1.37.8.2  nathanw 		} else {
   1310  1.37.8.2  nathanw 			memcpy(fd->sc_copybuf
   1311  1.37.8.2  nathanw 			    + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
   1312  1.37.8.2  nathanw 			    bp->b_data + fd->sc_skip, FDC_BSIZE);
   1313  1.37.8.2  nathanw 			fdc_dmastart(fdc, read, fd->sc_copybuf, 1024);
   1314  1.37.8.2  nathanw 		}
   1315  1.37.8.2  nathanw 		out_fdc(iot, ioh, NE7CMD_WRITE);	/* WRITE */
   1316  1.37.8.2  nathanw 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1317  1.37.8.2  nathanw 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
   1318  1.37.8.2  nathanw 		out_fdc(iot, ioh, head);
   1319  1.37.8.2  nathanw 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
   1320  1.37.8.2  nathanw 		out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */
   1321  1.37.8.2  nathanw 		out_fdc(iot, ioh, sectrac);		/* sectors/track */
   1322  1.37.8.2  nathanw 		out_fdc(iot, ioh, fd->sc_type->gap1);	/* gap1 size */
   1323  1.37.8.2  nathanw 		out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */
   1324  1.37.8.2  nathanw 		fdc->sc_state = IOCOMPLETE;
   1325  1.37.8.2  nathanw 		/* allow 2 seconds for operation */
   1326  1.37.8.2  nathanw 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1327  1.37.8.2  nathanw 		return 1;				/* will return later */
   1328  1.37.8.2  nathanw 
   1329  1.37.8.2  nathanw 	case SEEKWAIT:
   1330  1.37.8.2  nathanw 		callout_stop(&fdc->sc_timo_ch);
   1331  1.37.8.2  nathanw 		fdc->sc_state = SEEKCOMPLETE;
   1332  1.37.8.2  nathanw 		/* allow 1/50 second for heads to settle */
   1333  1.37.8.2  nathanw #if 0
   1334  1.37.8.2  nathanw 		callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
   1335  1.37.8.2  nathanw #endif
   1336  1.37.8.2  nathanw 		return 1;
   1337  1.37.8.2  nathanw 
   1338  1.37.8.2  nathanw 	case SEEKCOMPLETE:
   1339  1.37.8.2  nathanw 		/* Make sure seek really happened */
   1340  1.37.8.2  nathanw 		DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
   1341  1.37.8.2  nathanw 			 bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts)));
   1342  1.37.8.2  nathanw 		out_fdc(iot, ioh, NE7CMD_SENSEI);
   1343  1.37.8.2  nathanw 		tmp = fdcresult(fdc);
   1344  1.37.8.2  nathanw 		if ((st0 & 0xf8) == 0xc0) {
   1345  1.37.8.2  nathanw 			DPRINTF(("fdcintr: first seek!\n"));
   1346  1.37.8.2  nathanw 			fdc->sc_state = DORECAL;
   1347  1.37.8.2  nathanw 			goto loop;
   1348  1.37.8.2  nathanw 		} else if (tmp != 2 ||
   1349  1.37.8.2  nathanw 			   (st0 & 0xf8) != 0x20 ||
   1350  1.37.8.2  nathanw 			   cyl != bp->b_cylinder) {
   1351  1.37.8.2  nathanw #ifdef FDDEBUG
   1352  1.37.8.2  nathanw 			fdcstatus(&fd->sc_dev, 2, "seek failed");
   1353  1.37.8.2  nathanw #endif
   1354  1.37.8.2  nathanw 			fdcretry(fdc);
   1355  1.37.8.2  nathanw 			goto loop;
   1356  1.37.8.2  nathanw 		}
   1357  1.37.8.2  nathanw 		fd->sc_cylin = bp->b_cylinder;
   1358  1.37.8.2  nathanw 		goto doio;
   1359  1.37.8.2  nathanw 
   1360  1.37.8.2  nathanw 	case IOTIMEDOUT:
   1361  1.37.8.2  nathanw #if 0
   1362  1.37.8.2  nathanw 		isa_dmaabort(fdc->sc_drq);
   1363  1.37.8.2  nathanw #endif
   1364  1.37.8.2  nathanw 	case SEEKTIMEDOUT:
   1365  1.37.8.2  nathanw 	case RECALTIMEDOUT:
   1366  1.37.8.2  nathanw 	case RESETTIMEDOUT:
   1367  1.37.8.2  nathanw 		fdcretry(fdc);
   1368  1.37.8.2  nathanw 		goto loop;
   1369  1.37.8.2  nathanw 
   1370  1.37.8.2  nathanw 	case IOCOMPLETE: /* IO DONE, post-analyze */
   1371  1.37.8.2  nathanw 		callout_stop(&fdc->sc_timo_ch);
   1372  1.37.8.2  nathanw 		DPRINTF(("fdcintr: in IOCOMPLETE\n"));
   1373  1.37.8.2  nathanw 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
   1374  1.37.8.2  nathanw 			printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
   1375  1.37.8.2  nathanw #if 0
   1376  1.37.8.2  nathanw 			isa_dmaabort(fdc->sc_drq);
   1377  1.37.8.2  nathanw #endif
   1378  1.37.8.2  nathanw 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
   1379  1.37.8.2  nathanw 				  "read failed" : "write failed");
   1380  1.37.8.2  nathanw 			printf("blkno %d nblks %d\n",
   1381  1.37.8.2  nathanw 			    fd->sc_blkno, fd->sc_nblks);
   1382  1.37.8.2  nathanw 			fdcretry(fdc);
   1383  1.37.8.2  nathanw 			goto loop;
   1384  1.37.8.2  nathanw 		}
   1385  1.37.8.2  nathanw #if 0
   1386  1.37.8.2  nathanw 		isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
   1387  1.37.8.2  nathanw 		    nblks * FDC_BSIZE, fdc->sc_drq);
   1388  1.37.8.2  nathanw #endif
   1389  1.37.8.2  nathanw 	iocomplete2:
   1390  1.37.8.2  nathanw 		if (fdc->sc_errors) {
   1391  1.37.8.2  nathanw 			diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
   1392  1.37.8.2  nathanw 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
   1393  1.37.8.2  nathanw 			printf("\n");
   1394  1.37.8.2  nathanw 			fdc->sc_errors = 0;
   1395  1.37.8.2  nathanw 		}
   1396  1.37.8.2  nathanw 		fd->sc_blkno += fd->sc_nblks;
   1397  1.37.8.2  nathanw 		fd->sc_skip += fd->sc_nbytes;
   1398  1.37.8.2  nathanw 		fd->sc_bcount -= fd->sc_nbytes;
   1399  1.37.8.2  nathanw 		DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
   1400  1.37.8.2  nathanw 		if (fd->sc_bcount > 0) {
   1401  1.37.8.2  nathanw 			bp->b_cylinder = fd->sc_blkno
   1402  1.37.8.2  nathanw 				/ (fd->sc_type->seccyl
   1403  1.37.8.2  nathanw 				   * (1 << (fd->sc_type->secsize - 2)));
   1404  1.37.8.2  nathanw 			goto doseek;
   1405  1.37.8.2  nathanw 		}
   1406  1.37.8.2  nathanw 		fdfinish(fd, bp);
   1407  1.37.8.2  nathanw 		goto loop;
   1408  1.37.8.2  nathanw 
   1409  1.37.8.2  nathanw 	case COPYCOMPLETE: /* IO DONE, post-analyze */
   1410  1.37.8.2  nathanw 		DPRINTF(("fdcintr: COPYCOMPLETE:"));
   1411  1.37.8.2  nathanw 		callout_stop(&fdc->sc_timo_ch);
   1412  1.37.8.2  nathanw 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
   1413  1.37.8.2  nathanw 			printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
   1414  1.37.8.2  nathanw #if 0
   1415  1.37.8.2  nathanw 			isa_dmaabort(fdc->sc_drq);
   1416  1.37.8.2  nathanw #endif
   1417  1.37.8.2  nathanw 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
   1418  1.37.8.2  nathanw 				  "read failed" : "write failed");
   1419  1.37.8.2  nathanw 			printf("blkno %d nblks %d\n",
   1420  1.37.8.2  nathanw 			    fd->sc_blkno, fd->sc_nblks);
   1421  1.37.8.2  nathanw 			fdcretry(fdc);
   1422  1.37.8.2  nathanw 			goto loop;
   1423  1.37.8.2  nathanw 		}
   1424  1.37.8.2  nathanw 		goto doiohalf;
   1425  1.37.8.2  nathanw 
   1426  1.37.8.2  nathanw 	case DORESET:
   1427  1.37.8.2  nathanw 		DPRINTF(("fdcintr: in DORESET\n"));
   1428  1.37.8.2  nathanw 		/* try a reset, keep motor on */
   1429  1.37.8.2  nathanw 		fd_set_motor(fdc, 1);
   1430  1.37.8.2  nathanw 		DELAY(100);
   1431  1.37.8.2  nathanw 		fd_set_motor(fdc, 0);
   1432  1.37.8.2  nathanw 		fdc->sc_state = RESETCOMPLETE;
   1433  1.37.8.2  nathanw 		callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
   1434  1.37.8.2  nathanw 		return 1;			/* will return later */
   1435  1.37.8.2  nathanw 
   1436  1.37.8.2  nathanw 	case RESETCOMPLETE:
   1437  1.37.8.2  nathanw 		DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
   1438  1.37.8.2  nathanw 		callout_stop(&fdc->sc_timo_ch);
   1439  1.37.8.2  nathanw 		/* clear the controller output buffer */
   1440  1.37.8.2  nathanw 		for (i = 0; i < 4; i++) {
   1441  1.37.8.2  nathanw 			out_fdc(iot, ioh, NE7CMD_SENSEI);
   1442  1.37.8.2  nathanw 			(void) fdcresult(fdc);
   1443  1.37.8.2  nathanw 		}
   1444  1.37.8.2  nathanw 
   1445  1.37.8.2  nathanw 		/* fall through */
   1446  1.37.8.2  nathanw 	case DORECAL:
   1447  1.37.8.2  nathanw 		DPRINTF(("fdcintr: in DORECAL\n"));
   1448  1.37.8.2  nathanw 		out_fdc(iot, ioh, NE7CMD_RECAL);	/* recalibrate function */
   1449  1.37.8.2  nathanw 		out_fdc(iot, ioh, fd->sc_drive);
   1450  1.37.8.2  nathanw 		fdc->sc_state = RECALWAIT;
   1451  1.37.8.2  nathanw 		callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
   1452  1.37.8.2  nathanw 		return 1;			/* will return later */
   1453  1.37.8.2  nathanw 
   1454  1.37.8.2  nathanw 	case RECALWAIT:
   1455  1.37.8.2  nathanw 		DPRINTF(("fdcintr: in RECALWAIT\n"));
   1456  1.37.8.2  nathanw 		callout_stop(&fdc->sc_timo_ch);
   1457  1.37.8.2  nathanw 		fdc->sc_state = RECALCOMPLETE;
   1458  1.37.8.2  nathanw 		/* allow 1/30 second for heads to settle */
   1459  1.37.8.2  nathanw #if 0
   1460  1.37.8.2  nathanw 		callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
   1461  1.37.8.2  nathanw #endif
   1462  1.37.8.2  nathanw 		return 1;			/* will return later */
   1463  1.37.8.2  nathanw 
   1464  1.37.8.2  nathanw 	case RECALCOMPLETE:
   1465  1.37.8.2  nathanw 		DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
   1466  1.37.8.2  nathanw 		out_fdc(iot, ioh, NE7CMD_SENSEI);
   1467  1.37.8.2  nathanw 		tmp = fdcresult(fdc);
   1468  1.37.8.2  nathanw 		if ((st0 & 0xf8) == 0xc0) {
   1469  1.37.8.2  nathanw 			DPRINTF(("fdcintr: first seek!\n"));
   1470  1.37.8.2  nathanw 			fdc->sc_state = DORECAL;
   1471  1.37.8.2  nathanw 			goto loop;
   1472  1.37.8.2  nathanw 		} else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
   1473  1.37.8.2  nathanw #ifdef FDDEBUG
   1474  1.37.8.2  nathanw 			fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
   1475  1.37.8.2  nathanw #endif
   1476  1.37.8.2  nathanw 			fdcretry(fdc);
   1477  1.37.8.2  nathanw 			goto loop;
   1478  1.37.8.2  nathanw 		}
   1479  1.37.8.2  nathanw 		fd->sc_cylin = 0;
   1480  1.37.8.2  nathanw 		goto doseek;
   1481  1.37.8.2  nathanw 
   1482  1.37.8.2  nathanw 	case MOTORWAIT:
   1483  1.37.8.2  nathanw 		if (fd->sc_flags & FD_MOTOR_WAIT)
   1484  1.37.8.2  nathanw 			return 1;		/* time's not up yet */
   1485  1.37.8.2  nathanw 		goto doseek;
   1486  1.37.8.2  nathanw 
   1487  1.37.8.2  nathanw 	default:
   1488  1.37.8.2  nathanw 		fdcstatus(&fd->sc_dev, 0, "stray interrupt");
   1489  1.37.8.2  nathanw 		return 1;
   1490  1.37.8.2  nathanw 	}
   1491  1.37.8.2  nathanw #ifdef DIAGNOSTIC
   1492  1.37.8.2  nathanw 	panic("fdcintr: impossible");
   1493  1.37.8.2  nathanw #endif
   1494  1.37.8.2  nathanw #undef	st0
   1495  1.37.8.2  nathanw #undef	cyl
   1496  1.37.8.2  nathanw }
   1497  1.37.8.2  nathanw 
   1498  1.37.8.2  nathanw void
   1499  1.37.8.2  nathanw fdcretry(fdc)
   1500  1.37.8.2  nathanw 	struct fdc_softc *fdc;
   1501  1.37.8.2  nathanw {
   1502  1.37.8.2  nathanw 	struct fd_softc *fd;
   1503  1.37.8.2  nathanw 	struct buf *bp;
   1504  1.37.8.2  nathanw 	char bits[64];
   1505  1.37.8.2  nathanw 
   1506  1.37.8.2  nathanw 	DPRINTF(("fdcretry:\n"));
   1507  1.37.8.2  nathanw 	fd = fdc->sc_drives.tqh_first;
   1508  1.37.8.4  nathanw 	bp = BUFQ_PEEK(&fd->sc_q);
   1509  1.37.8.2  nathanw 
   1510  1.37.8.2  nathanw 	switch (fdc->sc_errors) {
   1511  1.37.8.2  nathanw 	case 0:
   1512  1.37.8.2  nathanw 		/* try again */
   1513  1.37.8.2  nathanw 		fdc->sc_state = SEEKCOMPLETE;
   1514  1.37.8.2  nathanw 		break;
   1515  1.37.8.2  nathanw 
   1516  1.37.8.2  nathanw 	case 1: case 2: case 3:
   1517  1.37.8.2  nathanw 		/* didn't work; try recalibrating */
   1518  1.37.8.2  nathanw 		fdc->sc_state = DORECAL;
   1519  1.37.8.2  nathanw 		break;
   1520  1.37.8.2  nathanw 
   1521  1.37.8.2  nathanw 	case 4:
   1522  1.37.8.2  nathanw 		/* still no go; reset the bastard */
   1523  1.37.8.2  nathanw 		fdc->sc_state = DORESET;
   1524  1.37.8.2  nathanw 		break;
   1525  1.37.8.2  nathanw 
   1526  1.37.8.2  nathanw 	default:
   1527  1.37.8.2  nathanw 		diskerr(bp, "fd", "hard error", LOG_PRINTF,
   1528  1.37.8.2  nathanw 			fd->sc_skip, (struct disklabel *)NULL);
   1529  1.37.8.2  nathanw 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
   1530  1.37.8.2  nathanw 						    NE7_ST0BITS, bits,
   1531  1.37.8.2  nathanw 						    sizeof(bits)));
   1532  1.37.8.2  nathanw 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
   1533  1.37.8.2  nathanw 						   NE7_ST1BITS, bits,
   1534  1.37.8.2  nathanw 						   sizeof(bits)));
   1535  1.37.8.2  nathanw 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
   1536  1.37.8.2  nathanw 						   NE7_ST2BITS, bits,
   1537  1.37.8.2  nathanw 						   sizeof(bits)));
   1538  1.37.8.2  nathanw 		printf(" cyl %d head %d sec %d)\n",
   1539  1.37.8.2  nathanw 		       fdc->sc_status[3],
   1540  1.37.8.2  nathanw 		       fdc->sc_status[4],
   1541  1.37.8.2  nathanw 		       fdc->sc_status[5]);
   1542  1.37.8.2  nathanw 
   1543  1.37.8.2  nathanw 		bp->b_flags |= B_ERROR;
   1544  1.37.8.2  nathanw 		bp->b_error = EIO;
   1545  1.37.8.2  nathanw 		fdfinish(fd, bp);
   1546  1.37.8.2  nathanw 	}
   1547  1.37.8.2  nathanw 	fdc->sc_errors++;
   1548  1.37.8.2  nathanw }
   1549  1.37.8.2  nathanw 
   1550  1.37.8.2  nathanw int
   1551  1.37.8.2  nathanw fdioctl(dev, cmd, addr, flag, p)
   1552  1.37.8.2  nathanw 	dev_t dev;
   1553  1.37.8.2  nathanw 	u_long cmd;
   1554  1.37.8.2  nathanw 	caddr_t addr;
   1555  1.37.8.2  nathanw 	int flag;
   1556  1.37.8.2  nathanw 	struct proc *p;
   1557  1.37.8.2  nathanw {
   1558  1.37.8.2  nathanw 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
   1559  1.37.8.2  nathanw 	struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
   1560  1.37.8.2  nathanw 	int unit = FDUNIT(dev);
   1561  1.37.8.2  nathanw 	int part = DISKPART(dev);
   1562  1.37.8.2  nathanw 	struct disklabel buffer;
   1563  1.37.8.2  nathanw 	int error;
   1564  1.37.8.2  nathanw 
   1565  1.37.8.2  nathanw 	DPRINTF(("fdioctl:\n"));
   1566  1.37.8.2  nathanw 	switch (cmd) {
   1567  1.37.8.2  nathanw 	case DIOCGDINFO:
   1568  1.37.8.2  nathanw #if 1
   1569  1.37.8.2  nathanw 		*(struct disklabel *)addr = *(fd->sc_dk.dk_label);
   1570  1.37.8.2  nathanw 		return(0);
   1571  1.37.8.2  nathanw #else
   1572  1.37.8.2  nathanw 		memset(&buffer, 0, sizeof(buffer));
   1573  1.37.8.2  nathanw 
   1574  1.37.8.2  nathanw 		buffer.d_secpercyl = fd->sc_type->seccyl;
   1575  1.37.8.2  nathanw 		buffer.d_type = DTYPE_FLOPPY;
   1576  1.37.8.2  nathanw 		buffer.d_secsize = 128 << fd->sc_type->secsize;
   1577  1.37.8.2  nathanw 
   1578  1.37.8.2  nathanw 		if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
   1579  1.37.8.2  nathanw 			return EINVAL;
   1580  1.37.8.2  nathanw 
   1581  1.37.8.2  nathanw 		*(struct disklabel *)addr = buffer;
   1582  1.37.8.2  nathanw 		return 0;
   1583  1.37.8.2  nathanw #endif
   1584  1.37.8.2  nathanw 
   1585  1.37.8.2  nathanw 	case DIOCGPART:
   1586  1.37.8.2  nathanw 		((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
   1587  1.37.8.2  nathanw 		((struct partinfo *)addr)->part =
   1588  1.37.8.2  nathanw 		    &fd->sc_dk.dk_label->d_partitions[part];
   1589  1.37.8.2  nathanw 		return(0);
   1590  1.37.8.2  nathanw 
   1591  1.37.8.2  nathanw 	case DIOCWLABEL:
   1592  1.37.8.2  nathanw 		if ((flag & FWRITE) == 0)
   1593  1.37.8.2  nathanw 			return EBADF;
   1594  1.37.8.2  nathanw 		/* XXX do something */
   1595  1.37.8.2  nathanw 		return 0;
   1596  1.37.8.2  nathanw 
   1597  1.37.8.2  nathanw 	case DIOCWDINFO:
   1598  1.37.8.2  nathanw 		if ((flag & FWRITE) == 0)
   1599  1.37.8.2  nathanw 			return EBADF;
   1600  1.37.8.2  nathanw 
   1601  1.37.8.2  nathanw 		error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
   1602  1.37.8.2  nathanw 		if (error)
   1603  1.37.8.2  nathanw 			return error;
   1604  1.37.8.2  nathanw 
   1605  1.37.8.2  nathanw 		error = writedisklabel(dev, fdstrategy, &buffer, NULL);
   1606  1.37.8.2  nathanw 		return error;
   1607  1.37.8.2  nathanw 
   1608  1.37.8.2  nathanw 	case DIOCLOCK:
   1609  1.37.8.2  nathanw 		/*
   1610  1.37.8.2  nathanw 		 * Nothing to do here, really.
   1611  1.37.8.2  nathanw 		 */
   1612  1.37.8.2  nathanw 		return 0; /* XXX */
   1613  1.37.8.2  nathanw 
   1614  1.37.8.2  nathanw 	case DIOCEJECT:
   1615  1.37.8.2  nathanw 		if (*(int *)addr == 0) {
   1616  1.37.8.2  nathanw 			/*
   1617  1.37.8.2  nathanw 			 * Don't force eject: check that we are the only
   1618  1.37.8.2  nathanw 			 * partition open. If so, unlock it.
   1619  1.37.8.2  nathanw 			 */
   1620  1.37.8.2  nathanw 			if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 ||
   1621  1.37.8.2  nathanw 			    fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask !=
   1622  1.37.8.2  nathanw 			    fd->sc_dk.dk_openmask) {
   1623  1.37.8.2  nathanw 				return (EBUSY);
   1624  1.37.8.2  nathanw 			}
   1625  1.37.8.2  nathanw 		}
   1626  1.37.8.2  nathanw 		/* FALLTHROUGH */
   1627  1.37.8.2  nathanw 	case ODIOCEJECT:
   1628  1.37.8.2  nathanw 		fd_do_eject(fdc, unit);
   1629  1.37.8.2  nathanw 		return 0;
   1630  1.37.8.2  nathanw 
   1631  1.37.8.2  nathanw 	default:
   1632  1.37.8.2  nathanw 		return ENOTTY;
   1633  1.37.8.2  nathanw 	}
   1634  1.37.8.2  nathanw 
   1635  1.37.8.2  nathanw #ifdef DIAGNOSTIC
   1636  1.37.8.2  nathanw 	panic("fdioctl: impossible");
   1637  1.37.8.2  nathanw #endif
   1638  1.37.8.2  nathanw }
   1639  1.37.8.2  nathanw 
   1640  1.37.8.2  nathanw void
   1641  1.37.8.2  nathanw fd_do_eject(fdc, unit)
   1642  1.37.8.2  nathanw 	struct fdc_softc *fdc;
   1643  1.37.8.2  nathanw 	int unit;
   1644  1.37.8.2  nathanw {
   1645  1.37.8.2  nathanw 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
   1646  1.37.8.2  nathanw 			  0x20 | ( 1 << unit));
   1647  1.37.8.2  nathanw 	DELAY(1); /* XXX */
   1648  1.37.8.2  nathanw 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20);
   1649  1.37.8.2  nathanw }
   1650  1.37.8.2  nathanw 
   1651  1.37.8.2  nathanw /*
   1652  1.37.8.2  nathanw  * Build disk label. For now we only create a label from what we know
   1653  1.37.8.2  nathanw  * from 'sc'.
   1654  1.37.8.2  nathanw  */
   1655  1.37.8.2  nathanw static int
   1656  1.37.8.2  nathanw fdgetdisklabel(sc, dev)
   1657  1.37.8.2  nathanw 	struct fd_softc *sc;
   1658  1.37.8.2  nathanw 	dev_t dev;
   1659  1.37.8.2  nathanw {
   1660  1.37.8.2  nathanw 	struct disklabel *lp;
   1661  1.37.8.2  nathanw 	int part;
   1662  1.37.8.2  nathanw 
   1663  1.37.8.2  nathanw 	DPRINTF(("fdgetdisklabel()\n"));
   1664  1.37.8.2  nathanw 
   1665  1.37.8.2  nathanw 	part = DISKPART(dev);
   1666  1.37.8.2  nathanw 	lp = sc->sc_dk.dk_label;
   1667  1.37.8.2  nathanw 	memset(lp, 0, sizeof(struct disklabel));
   1668  1.37.8.2  nathanw 
   1669  1.37.8.2  nathanw 	lp->d_secsize     = 128 << sc->sc_type->secsize;
   1670  1.37.8.2  nathanw 	lp->d_ntracks     = sc->sc_type->heads;
   1671  1.37.8.2  nathanw 	lp->d_nsectors    = sc->sc_type->sectrac;
   1672  1.37.8.2  nathanw 	lp->d_secpercyl   = lp->d_ntracks * lp->d_nsectors;
   1673  1.37.8.2  nathanw 	lp->d_ncylinders  = sc->sc_type->size / lp->d_secpercyl;
   1674  1.37.8.2  nathanw 	lp->d_secperunit  = sc->sc_type->size;
   1675  1.37.8.2  nathanw 
   1676  1.37.8.2  nathanw 	lp->d_type        = DTYPE_FLOPPY;
   1677  1.37.8.2  nathanw 	lp->d_rpm         = 300; 	/* XXX */
   1678  1.37.8.2  nathanw 	lp->d_interleave  = 1;		/* FIXME: is this OK?		*/
   1679  1.37.8.2  nathanw 	lp->d_bbsize      = 0;
   1680  1.37.8.2  nathanw 	lp->d_sbsize      = 0;
   1681  1.37.8.2  nathanw 	lp->d_npartitions = part + 1;
   1682  1.37.8.2  nathanw #define STEP_DELAY	6000	/* 6ms (6000us) delay after stepping	*/
   1683  1.37.8.2  nathanw 	lp->d_trkseek     = STEP_DELAY; /* XXX */
   1684  1.37.8.2  nathanw 	lp->d_magic       = DISKMAGIC;
   1685  1.37.8.2  nathanw 	lp->d_magic2      = DISKMAGIC;
   1686  1.37.8.2  nathanw 	lp->d_checksum    = dkcksum(lp);
   1687  1.37.8.2  nathanw 	lp->d_partitions[part].p_size   = lp->d_secperunit;
   1688  1.37.8.2  nathanw 	lp->d_partitions[part].p_fstype = FS_UNUSED;
   1689  1.37.8.2  nathanw 	lp->d_partitions[part].p_fsize  = 1024;
   1690  1.37.8.2  nathanw 	lp->d_partitions[part].p_frag   = 8;
   1691  1.37.8.2  nathanw 
   1692  1.37.8.2  nathanw 	return(0);
   1693  1.37.8.2  nathanw }
   1694  1.37.8.2  nathanw 
   1695  1.37.8.2  nathanw #include <dev/cons.h>
   1696  1.37.8.2  nathanw 
   1697  1.37.8.2  nathanw /*
   1698  1.37.8.2  nathanw  * Mountroot hook: prompt the user to enter the root file system
   1699  1.37.8.2  nathanw  * floppy.
   1700  1.37.8.2  nathanw  */
   1701  1.37.8.2  nathanw void
   1702  1.37.8.2  nathanw fd_mountroot_hook(dev)
   1703  1.37.8.2  nathanw 	struct device *dev;
   1704  1.37.8.2  nathanw {
   1705  1.37.8.2  nathanw 	struct fd_softc *fd = (void*) dev;
   1706  1.37.8.2  nathanw 	struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
   1707  1.37.8.2  nathanw 	int c;
   1708  1.37.8.2  nathanw 
   1709  1.37.8.2  nathanw 	fd_do_eject(fdc, dev->dv_unit);
   1710  1.37.8.2  nathanw 	printf("Insert filesystem floppy and press return.");
   1711  1.37.8.2  nathanw 	for (;;) {
   1712  1.37.8.2  nathanw 		c = cngetc();
   1713  1.37.8.2  nathanw 		if ((c == '\r') || (c == '\n')) {
   1714  1.37.8.2  nathanw 			printf("\n");
   1715  1.37.8.2  nathanw 			break;
   1716  1.37.8.2  nathanw 		}
   1717  1.37.8.2  nathanw 	}
   1718  1.37.8.2  nathanw }
   1719