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