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