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