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