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