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