Home | History | Annotate | Line # | Download | only in dev
hdfd.c revision 1.24.4.1
      1 /*	$NetBSD: hdfd.c,v 1.24.4.1 2000/09/06 09:33:07 leo 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 
     83 #include <vm/vm.h>
     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 tranferring */
    231 	int		sc_nbytes;	/* #bytes currently tranferring */
    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((dev_t, struct ne7_fd_formb *, struct proc *));
    278 
    279 static void	fdgetdisklabel __P((struct fd_softc *, dev_t));
    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 = hdfd_cd.cd_devs[FDUNIT(bp->b_dev)];
    570 	int sz;
    571  	int s;
    572 
    573 	/* Valid unit, controller, and request? */
    574 	if (bp->b_blkno < 0 ||
    575 	    ((bp->b_bcount % FDC_BSIZE) != 0 &&
    576 	     (bp->b_flags & B_FORMAT) == 0)) {
    577 		bp->b_error = EINVAL;
    578 		goto bad;
    579 	}
    580 
    581 	/* If it's a null transfer, return immediately. */
    582 	if (bp->b_bcount == 0)
    583 		goto done;
    584 
    585 	sz = howmany(bp->b_bcount, FDC_BSIZE);
    586 
    587 	if (bp->b_blkno + sz > fd->sc_type->size) {
    588 		sz = fd->sc_type->size - bp->b_blkno;
    589 		if (sz == 0) {
    590 			/* If exactly at end of disk, return EOF. */
    591 			goto done;
    592 		}
    593 		if (sz < 0) {
    594 			/* If past end of disk, return EINVAL. */
    595 			bp->b_error = EINVAL;
    596 			goto bad;
    597 		}
    598 		/* Otherwise, truncate request. */
    599 		bp->b_bcount = sz << DEV_BSHIFT;
    600 	}
    601 
    602 	bp->b_rawblkno = bp->b_blkno;
    603  	bp->b_cylinder = bp->b_blkno / (FDC_BSIZE/DEV_BSIZE) / fd->sc_type->seccyl;
    604 
    605 #ifdef FD_DEBUG
    606 	printf("fdstrategy: b_blkno %d b_bcount %ld blkno %ld cylin %ld sz"
    607 		" %d\n", bp->b_blkno, bp->b_bcount, (long)fd->sc_blkno,
    608 		bp->b_cylinder, sz);
    609 #endif
    610 
    611 	/* Queue transfer on drive, activate drive and controller if idle. */
    612 	s = splbio();
    613 	disksort_cylinder(&fd->sc_q, bp);
    614 	callout_stop(&fd->sc_motoroff_ch);		/* a good idea */
    615 	if (fd->sc_active == 0)
    616 		fdstart(fd);
    617 #ifdef DIAGNOSTIC
    618 	else {
    619 		struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    620 		if (fdc->sc_state == DEVIDLE) {
    621 			printf("fdstrategy: controller inactive\n");
    622 			fdcstart(fdc);
    623 		}
    624 	}
    625 #endif
    626 	splx(s);
    627 	return;
    628 
    629 bad:
    630 	bp->b_flags |= B_ERROR;
    631 done:
    632 	/* Toss transfer; we're done early. */
    633 	bp->b_resid = bp->b_bcount;
    634 	biodone(bp);
    635 }
    636 
    637 void
    638 fdstart(fd)
    639 	struct fd_softc *fd;
    640 {
    641 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    642 	int active = fdc->sc_drives.tqh_first != 0;
    643 
    644 	/* Link into controller queue. */
    645 	fd->sc_active = 1;
    646 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    647 
    648 	/* If controller not already active, start it. */
    649 	if (!active)
    650 		fdcstart(fdc);
    651 }
    652 
    653 void
    654 fdfinish(fd, bp)
    655 	struct fd_softc *fd;
    656 	struct buf *bp;
    657 {
    658 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    659 
    660 	/*
    661 	 * Move this drive to the end of the queue to give others a `fair'
    662 	 * chance.  We only force a switch if N operations are completed while
    663 	 * another drive is waiting to be serviced, since there is a long motor
    664 	 * startup delay whenever we switch.
    665 	 */
    666 	if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
    667 		fd->sc_ops = 0;
    668 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
    669 		if (BUFQ_NEXT(bp) != NULL)
    670 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    671 		else
    672 			fd->sc_active = 0;
    673 	}
    674 	bp->b_resid = fd->sc_bcount;
    675 	fd->sc_skip = 0;
    676 	BUFQ_REMOVE(&fd->sc_q, bp);
    677 
    678 	biodone(bp);
    679 	/* turn off motor 5s from now */
    680 	callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
    681 	fdc->sc_state = DEVIDLE;
    682 }
    683 
    684 int
    685 fdread(dev, uio, flags)
    686 	dev_t dev;
    687 	struct uio *uio;
    688 	int flags;
    689 {
    690 	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
    691 }
    692 
    693 int
    694 fdwrite(dev, uio, flags)
    695 	dev_t dev;
    696 	struct uio *uio;
    697 	int flags;
    698 {
    699 	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
    700 }
    701 
    702 void
    703 fd_set_motor(fdc, reset)
    704 	struct fdc_softc *fdc;
    705 	int reset;
    706 {
    707 	struct fd_softc *fd;
    708 	u_char status;
    709 	int n;
    710 
    711 	if ((fd = fdc->sc_drives.tqh_first) != NULL)
    712 		status = fd->sc_drive;
    713 	else
    714 		status = 0;
    715 	if (!reset)
    716 		status |= FDO_FRST | FDO_FDMAEN;
    717 	for (n = 0; n < 4; n++)
    718 		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
    719 			status |= FDO_MOEN(n);
    720 	wrt_fdc_reg(fdout, status);
    721 }
    722 
    723 void
    724 fd_motor_off(arg)
    725 	void *arg;
    726 {
    727 	struct fd_softc *fd = arg;
    728 	int s;
    729 
    730 	s = splbio();
    731 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
    732 	fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0);
    733 	splx(s);
    734 }
    735 
    736 void
    737 fd_motor_on(arg)
    738 	void *arg;
    739 {
    740 	struct fd_softc *fd = arg;
    741 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    742 	int s;
    743 
    744 	s = splbio();
    745 	fd->sc_flags &= ~FD_MOTOR_WAIT;
    746 	if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
    747 		(void) fdcintr(fdc);
    748 	splx(s);
    749 }
    750 
    751 int
    752 fdcresult(fdc)
    753 	struct fdc_softc *fdc;
    754 {
    755 	u_char i;
    756 	int j = 100000,
    757 	    n = 0;
    758 
    759 	for (; j; j--) {
    760 		i = rd_fdc_reg(fdsts) & (NE7_DIO | NE7_RQM | NE7_CB);
    761 		if (i == NE7_RQM)
    762 			return n;
    763 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
    764 			if (n >= sizeof(fdc->sc_status)) {
    765 				log(LOG_ERR, "fdcresult: overrun\n");
    766 				return -1;
    767 			}
    768 			fdc->sc_status[n++] = rd_fdc_reg(fddata);
    769 		}
    770 		else delay(10);
    771 	}
    772 	log(LOG_ERR, "fdcresult: timeout\n");
    773 	return -1;
    774 }
    775 
    776 int
    777 out_fdc(x)
    778 	u_char x;
    779 {
    780 	int i = 100000;
    781 
    782 	while (((rd_fdc_reg(fdsts) & (NE7_DIO|NE7_RQM)) != NE7_RQM) && i-- > 0)
    783 		delay(1);
    784 	if (i <= 0)
    785 		return -1;
    786 	wrt_fdc_reg(fddata, x);
    787 	return 0;
    788 }
    789 
    790 int
    791 fdopen(dev, flags, mode, p)
    792 	dev_t dev;
    793 	int flags;
    794 	int mode;
    795 	struct proc *p;
    796 {
    797  	int unit;
    798 	struct fd_softc *fd;
    799 	struct fd_type *type;
    800 
    801 	unit = FDUNIT(dev);
    802 	if (unit >= hdfd_cd.cd_ndevs)
    803 		return ENXIO;
    804 	fd = hdfd_cd.cd_devs[unit];
    805 	if (fd == 0)
    806 		return ENXIO;
    807 	type = fd_dev_to_type(fd, dev);
    808 	if (type == NULL)
    809 		return ENXIO;
    810 
    811 	if ((fd->sc_flags & FD_OPEN) != 0 &&
    812 	    fd->sc_type != type)
    813 		return EBUSY;
    814 
    815 	fd->sc_type = type;
    816 	fd->sc_cylin = -1;
    817 	fd->sc_flags |= FD_OPEN;
    818 	fdgetdisklabel(fd, dev);
    819 
    820 	return 0;
    821 }
    822 
    823 int
    824 fdclose(dev, flags, mode, p)
    825 	dev_t dev;
    826 	int flags;
    827 	int mode;
    828 	struct proc *p;
    829 {
    830 	struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(dev)];
    831 
    832 	fd->sc_flags &= ~(FD_OPEN|FD_HAVELAB);
    833 	fd->sc_opts  &= ~(FDOPT_NORETRY|FDOPT_SILENT);
    834 	return 0;
    835 }
    836 
    837 void
    838 fdcstart(fdc)
    839 	struct fdc_softc *fdc;
    840 {
    841 
    842 #ifdef DIAGNOSTIC
    843 	/* only got here if controller's drive queue was inactive; should
    844 	   be in idle state */
    845 	if (fdc->sc_state != DEVIDLE) {
    846 		printf("fdcstart: not idle\n");
    847 		return;
    848 	}
    849 #endif
    850 	(void) fdcintr(fdc);
    851 }
    852 
    853 void
    854 fdcstatus(dv, n, s)
    855 	struct device *dv;
    856 	int n;
    857 	char *s;
    858 {
    859 	struct fdc_softc *fdc = (void *)dv->dv_parent;
    860 	char bits[64];
    861 
    862 	if (n == 0) {
    863 		out_fdc(NE7CMD_SENSEI);
    864 		(void) fdcresult(fdc);
    865 		n = 2;
    866 	}
    867 
    868 	printf("%s: %s", dv->dv_xname, s);
    869 
    870 	switch (n) {
    871 	case 0:
    872 		printf("\n");
    873 		break;
    874 	case 2:
    875 		printf(" (st0 %s cyl %d)\n",
    876 		    bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
    877 		    bits, sizeof(bits)), fdc->sc_status[1]);
    878 		break;
    879 	case 7:
    880 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
    881 		    NE7_ST0BITS, bits, sizeof(bits)));
    882 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
    883 		    NE7_ST1BITS, bits, sizeof(bits)));
    884 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
    885 		    NE7_ST2BITS, bits, sizeof(bits)));
    886 		printf(" cyl %d head %d sec %d)\n",
    887 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
    888 		break;
    889 #ifdef DIAGNOSTIC
    890 	default:
    891 		printf("\nfdcstatus: weird size");
    892 		break;
    893 #endif
    894 	}
    895 }
    896 
    897 void
    898 fdctimeout(arg)
    899 	void *arg;
    900 {
    901 	struct fdc_softc *fdc = arg;
    902 	struct fd_softc *fd = fdc->sc_drives.tqh_first;
    903 	int s;
    904 
    905 	s = splbio();
    906 	fdcstatus(&fd->sc_dev, 0, "timeout");
    907 
    908 	if (BUFQ_FIRST(&fd->sc_q) != NULL)
    909 		fdc->sc_state++;
    910 	else
    911 		fdc->sc_state = DEVIDLE;
    912 
    913 	(void) fdcintr(fdc);
    914 	splx(s);
    915 }
    916 
    917 void
    918 fdcpseudointr(arg)
    919 	void *arg;
    920 {
    921 	int s;
    922 
    923 	/* Just ensure it has the right spl. */
    924 	s = splbio();
    925 	(void) fdcintr(arg);
    926 	splx(s);
    927 }
    928 
    929 int
    930 fdcintr(arg)
    931 	void *arg;
    932 {
    933 	struct fdc_softc	*fdc = arg;
    934 #define	st0	fdc->sc_status[0]
    935 #define	st1	fdc->sc_status[1]
    936 #define	cyl	fdc->sc_status[1]
    937 
    938 	struct fd_softc		*fd;
    939 	struct buf		*bp;
    940 	int			read, head, sec, i, nblks;
    941 	struct fd_type		*type;
    942 	struct ne7_fd_formb	*finfo = NULL;
    943 
    944 loop:
    945 	/* Is there a drive for the controller to do a transfer with? */
    946 	fd = fdc->sc_drives.tqh_first;
    947 	if (fd == NULL) {
    948 		fdc->sc_state = DEVIDLE;
    949  		return 1;
    950 	}
    951 
    952 	/* Is there a transfer to this drive?  If not, deactivate drive. */
    953 	bp = BUFQ_FIRST(&fd->sc_q);
    954 	if (bp == NULL) {
    955 		fd->sc_ops = 0;
    956 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
    957 		fd->sc_active = 0;
    958 		goto loop;
    959 	}
    960 
    961 	if (bp->b_flags & B_FORMAT)
    962 		finfo = (struct ne7_fd_formb *)bp->b_data;
    963 
    964 	switch (fdc->sc_state) {
    965 	case DEVIDLE:
    966 		fdc->sc_errors = 0;
    967 		fdc->sc_overruns = 0;
    968 		fd->sc_skip = 0;
    969 		fd->sc_bcount = bp->b_bcount;
    970 		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
    971 		callout_stop(&fd->sc_motoroff_ch);
    972 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
    973 			fdc->sc_state = MOTORWAIT;
    974 			return 1;
    975 		}
    976 		if ((fd->sc_flags & FD_MOTOR) == 0) {
    977 			/* Turn on the motor, being careful about pairing. */
    978 			struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
    979 			if (ofd && ofd->sc_flags & FD_MOTOR) {
    980 				callout_stop(&ofd->sc_motoroff_ch);
    981 				ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
    982 			}
    983 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
    984 			fd_set_motor(fdc, 0);
    985 			fdc->sc_state = MOTORWAIT;
    986 			/* Allow .25s for motor to stabilize. */
    987 			callout_reset(&fd->sc_motoron_ch, hz / 4,
    988 			    fd_motor_on, fd);
    989 			return 1;
    990 		}
    991 		/* Make sure the right drive is selected. */
    992 		fd_set_motor(fdc, 0);
    993 
    994 		/* fall through */
    995 	case DOSEEK:
    996 	doseek:
    997 		if (fd->sc_cylin == bp->b_cylinder)
    998 			goto doio;
    999 
   1000 		out_fdc(NE7CMD_SPECIFY);/* specify command */
   1001 		out_fdc(fd->sc_type->steprate);
   1002 		out_fdc(0x7);	/* XXX head load time == 6ms - non-dma */
   1003 
   1004 		fdc_ienable();
   1005 
   1006 		out_fdc(NE7CMD_SEEK);	/* seek function */
   1007 		out_fdc(fd->sc_drive);	/* drive number */
   1008 		out_fdc(bp->b_cylinder * fd->sc_type->step);
   1009 
   1010 		fd->sc_cylin = -1;
   1011 		fdc->sc_state = SEEKWAIT;
   1012 
   1013 		fd->sc_dk.dk_seek++;
   1014 		disk_busy(&fd->sc_dk);
   1015 
   1016 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
   1017 		return 1;
   1018 
   1019 	case DOIO:
   1020 	doio:
   1021 		if (finfo)
   1022 			fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
   1023 				      (char *)finfo;
   1024 
   1025 		type  = fd->sc_type;
   1026 		sec   = fd->sc_blkno % type->seccyl;
   1027 		head  = sec / type->sectrac;
   1028 		sec  -= head * type->sectrac;
   1029 		nblks = type->sectrac - sec;
   1030 		nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
   1031 		nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
   1032 		fd->sc_nblks  = nblks;
   1033 		fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
   1034 #ifdef DIAGNOSTIC
   1035 		{
   1036 		     int block;
   1037 
   1038 		     block = (fd->sc_cylin * type->heads + head)
   1039 				* type->sectrac + sec;
   1040 		     if (block != fd->sc_blkno) {
   1041 			 printf("fdcintr: block %d != blkno %d\n",
   1042 						block, fd->sc_blkno);
   1043 #ifdef DDB
   1044 			 Debugger();
   1045 #endif
   1046 		     }
   1047 		}
   1048 #endif
   1049 		read = bp->b_flags & B_READ ? 1 : 0;
   1050 
   1051 		/*
   1052 		 * Setup pseudo-dma address & count
   1053 		 */
   1054 		fddmaaddr = bp->b_data + fd->sc_skip;
   1055 		fddmalen  = fd->sc_nbytes;
   1056 
   1057 		wrt_fdc_reg(fdctl, type->rate);
   1058 #ifdef FD_DEBUG
   1059 		printf("fdcintr: %s drive %d track %d head %d sec %d"
   1060 			" nblks %d\n", read ? "read" : "write",
   1061 			fd->sc_drive, fd->sc_cylin, head, sec, nblks);
   1062 #endif
   1063 		fdc_ienable();
   1064 
   1065 		if (finfo) {
   1066 			/* formatting */
   1067 			if (out_fdc(NE7CMD_FORMAT) < 0) {
   1068 				fdc->sc_errors = 4;
   1069 				fdcretry(fdc);
   1070 				goto loop;
   1071 			}
   1072 			out_fdc((head << 2) | fd->sc_drive);
   1073 			out_fdc(finfo->fd_formb_secshift);
   1074 			out_fdc(finfo->fd_formb_nsecs);
   1075 			out_fdc(finfo->fd_formb_gaplen);
   1076 			out_fdc(finfo->fd_formb_fillbyte);
   1077 		} else {
   1078 			if (read)
   1079 				out_fdc(NE7CMD_READ);	/* READ */
   1080 			else
   1081 				out_fdc(NE7CMD_WRITE);	/* WRITE */
   1082 			out_fdc((head << 2) | fd->sc_drive);
   1083 			out_fdc(fd->sc_cylin);		/* track	 */
   1084 			out_fdc(head);			/* head		 */
   1085 			out_fdc(sec + 1);		/* sector +1	 */
   1086 			out_fdc(type->secsize);		/* sector size   */
   1087 			out_fdc(sec + nblks);		/* last sectors	 */
   1088 			out_fdc(type->gap1);		/* gap1 size	 */
   1089 			out_fdc(type->datalen);		/* data length	 */
   1090 		}
   1091 		fdc->sc_state = IOCOMPLETE;
   1092 
   1093 		disk_busy(&fd->sc_dk);
   1094 
   1095 		/* allow 2 seconds for operation */
   1096 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1097 		return 1;				/* will return later */
   1098 
   1099 	case SEEKWAIT:
   1100 		callout_stop(&fdc->sc_timo_ch);
   1101 		fdc->sc_state = SEEKCOMPLETE;
   1102 		/* allow 1/50 second for heads to settle */
   1103 		callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
   1104 		return 1;
   1105 
   1106 	case SEEKCOMPLETE:
   1107 		disk_unbusy(&fd->sc_dk, 0);	/* no data on seek */
   1108 
   1109 		/* Make sure seek really happened. */
   1110 		out_fdc(NE7CMD_SENSEI);
   1111 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
   1112 		    cyl != bp->b_cylinder * fd->sc_type->step) {
   1113 #ifdef FD_DEBUG
   1114 			fdcstatus(&fd->sc_dev, 2, "seek failed");
   1115 #endif
   1116 			fdcretry(fdc);
   1117 			goto loop;
   1118 		}
   1119 		fd->sc_cylin = bp->b_cylinder;
   1120 		goto doio;
   1121 
   1122 	case IOTIMEDOUT:
   1123 	case SEEKTIMEDOUT:
   1124 	case RECALTIMEDOUT:
   1125 	case RESETTIMEDOUT:
   1126 		fdcretry(fdc);
   1127 		goto loop;
   1128 
   1129 	case IOCOMPLETE: /* IO DONE, post-analyze */
   1130 		callout_stop(&fdc->sc_timo_ch);
   1131 
   1132 		disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid));
   1133 
   1134 		if (fdcresult(fdc) != 7 || (st1 & 0x37) != 0) {
   1135 			/*
   1136 			 * As the damn chip doesn't seem to have a FIFO,
   1137 			 * accept a few overruns as a fact of life *sigh*
   1138 			 */
   1139 			if ((st1 & 0x10) && (++fdc->sc_overruns < 4)) {
   1140 				fdc->sc_state = DOSEEK;
   1141 				goto loop;
   1142 			}
   1143 #ifdef FD_DEBUG
   1144 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
   1145 			    "read failed" : "write failed");
   1146 			printf("blkno %d nblks %d\n",
   1147 			    fd->sc_blkno, fd->sc_nblks);
   1148 #endif
   1149 			fdcretry(fdc);
   1150 			goto loop;
   1151 		}
   1152 		if (fdc->sc_errors) {
   1153 			diskerr(bp, "fd", "soft error", LOG_PRINTF,
   1154 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
   1155 			printf("\n");
   1156 			fdc->sc_errors = 0;
   1157 		}
   1158 		fdc->sc_overruns = 0;
   1159 		fd->sc_blkno += fd->sc_nblks;
   1160 		fd->sc_skip += fd->sc_nbytes;
   1161 		fd->sc_bcount -= fd->sc_nbytes;
   1162 		if (!finfo && fd->sc_bcount > 0) {
   1163 			bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
   1164 			goto doseek;
   1165 		}
   1166 		fdfinish(fd, bp);
   1167 		goto loop;
   1168 
   1169 	case DORESET:
   1170 		/* try a reset, keep motor on */
   1171 		fd_set_motor(fdc, 1);
   1172 		delay(100);
   1173 		fd_set_motor(fdc, 0);
   1174 		fdc->sc_state = RESETCOMPLETE;
   1175 		callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
   1176 		return 1;			/* will return later */
   1177 
   1178 	case RESETCOMPLETE:
   1179 		callout_stop(&fdc->sc_timo_ch);
   1180 		/* clear the controller output buffer */
   1181 		for (i = 0; i < 4; i++) {
   1182 			out_fdc(NE7CMD_SENSEI);
   1183 			(void) fdcresult(fdc);
   1184 		}
   1185 
   1186 		/* fall through */
   1187 	case DORECAL:
   1188 		fdc_ienable();
   1189 
   1190 		out_fdc(NE7CMD_RECAL);	/* recalibrate function */
   1191 		out_fdc(fd->sc_drive);
   1192 		fdc->sc_state = RECALWAIT;
   1193 		callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
   1194 		return 1;			/* will return later */
   1195 
   1196 	case RECALWAIT:
   1197 		callout_stop(&fdc->sc_timo_ch);
   1198 		fdc->sc_state = RECALCOMPLETE;
   1199 		/* allow 1/30 second for heads to settle */
   1200 		callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
   1201 		return 1;			/* will return later */
   1202 
   1203 	case RECALCOMPLETE:
   1204 		out_fdc(NE7CMD_SENSEI);
   1205 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
   1206 #ifdef FD_DEBUG
   1207 			fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
   1208 #endif
   1209 			fdcretry(fdc);
   1210 			goto loop;
   1211 		}
   1212 		fd->sc_cylin = 0;
   1213 		goto doseek;
   1214 
   1215 	case MOTORWAIT:
   1216 		if (fd->sc_flags & FD_MOTOR_WAIT)
   1217 			return 1;		/* time's not up yet */
   1218 		goto doseek;
   1219 
   1220 	default:
   1221 		fdcstatus(&fd->sc_dev, 0, "stray interrupt");
   1222 		return 1;
   1223 	}
   1224 #ifdef DIAGNOSTIC
   1225 	panic("fdcintr: impossible");
   1226 #endif
   1227 #undef	st0
   1228 #undef	st1
   1229 #undef	cyl
   1230 }
   1231 
   1232 void
   1233 fdcretry(fdc)
   1234 	struct fdc_softc *fdc;
   1235 {
   1236 	char bits[64];
   1237 	struct fd_softc *fd;
   1238 	struct buf *bp;
   1239 
   1240 	fd = fdc->sc_drives.tqh_first;
   1241 	bp = BUFQ_FIRST(&fd->sc_q);
   1242 
   1243 	if (fd->sc_opts & FDOPT_NORETRY)
   1244 	    goto fail;
   1245 
   1246 	switch (fdc->sc_errors) {
   1247 	case 0:
   1248 		/* try again */
   1249 		fdc->sc_state = DOSEEK;
   1250 		break;
   1251 
   1252 	case 1: case 2: case 3:
   1253 		/* didn't work; try recalibrating */
   1254 		fdc->sc_state = DORECAL;
   1255 		break;
   1256 
   1257 	case 4:
   1258 		/* still no go; reset the bastard */
   1259 		fdc->sc_state = DORESET;
   1260 		break;
   1261 
   1262 	default:
   1263 	fail:
   1264 		if ((fd->sc_opts & FDOPT_SILENT) == 0) {
   1265 			diskerr(bp, "fd", "hard error", LOG_PRINTF,
   1266 				fd->sc_skip / FDC_BSIZE,
   1267 				(struct disklabel *)NULL);
   1268 
   1269 			printf(" (st0 %s",
   1270 			       bitmask_snprintf(fdc->sc_status[0],
   1271 						NE7_ST0BITS, bits,
   1272 						sizeof(bits)));
   1273 			printf(" st1 %s",
   1274 			       bitmask_snprintf(fdc->sc_status[1],
   1275 						NE7_ST1BITS, bits,
   1276 						sizeof(bits)));
   1277 			printf(" st2 %s",
   1278 			       bitmask_snprintf(fdc->sc_status[2],
   1279 						NE7_ST2BITS, bits,
   1280 						sizeof(bits)));
   1281 			printf(" cyl %d head %d sec %d)\n",
   1282 			       fdc->sc_status[3],
   1283 			       fdc->sc_status[4],
   1284 			       fdc->sc_status[5]);
   1285 		}
   1286 		bp->b_flags |= B_ERROR;
   1287 		bp->b_error = EIO;
   1288 		fdfinish(fd, bp);
   1289 	}
   1290 	fdc->sc_errors++;
   1291 }
   1292 
   1293 int
   1294 fdsize(dev)
   1295 	dev_t dev;
   1296 {
   1297 
   1298 	/* Swapping to floppies would not make sense. */
   1299 	return -1;
   1300 }
   1301 
   1302 int
   1303 fddump(dev, blkno, va, size)
   1304 	dev_t dev;
   1305 	daddr_t blkno;
   1306 	caddr_t va;
   1307 	size_t size;
   1308 {
   1309 
   1310 	/* Not implemented. */
   1311 	return ENXIO;
   1312 }
   1313 
   1314 int
   1315 fdioctl(dev, cmd, addr, flag, p)
   1316 	dev_t dev;
   1317 	u_long cmd;
   1318 	caddr_t addr;
   1319 	int flag;
   1320 	struct proc *p;
   1321 {
   1322 	struct fd_softc		*fd;
   1323 	struct disklabel	buffer;
   1324 	int			error;
   1325 	struct fdformat_parms	*form_parms;
   1326 	struct fdformat_cmd	*form_cmd;
   1327 	struct ne7_fd_formb	fd_formb;
   1328 	unsigned int		scratch;
   1329 	int			il[FD_MAX_NSEC + 1];
   1330 	register int		i, j;
   1331 
   1332 	fd = hdfd_cd.cd_devs[FDUNIT(dev)];
   1333 
   1334 	switch (cmd) {
   1335 	case DIOCGDINFO:
   1336 		fdgetdisklabel(fd, dev);
   1337 		*(struct disklabel *)addr = *(fd->sc_dk.dk_label);
   1338 		return 0;
   1339 
   1340 	case DIOCGPART:
   1341 		fdgetdisklabel(fd, dev);
   1342 		((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
   1343 		((struct partinfo *)addr)->part =
   1344 			      &fd->sc_dk.dk_label->d_partitions[RAW_PART];
   1345 		return(0);
   1346 
   1347 	case DIOCWLABEL:
   1348 		if ((flag & FWRITE) == 0)
   1349 			return EBADF;
   1350 		/* XXX do something */
   1351 		return 0;
   1352 
   1353 	case DIOCSDINFO:
   1354 	case DIOCWDINFO:
   1355 		if ((flag & FWRITE) == 0)
   1356 		    return EBADF;
   1357 
   1358 		fd->sc_flags &= ~FD_HAVELAB;   /* Invalid */
   1359 		error = setdisklabel(&buffer, (struct disklabel *)addr, 0,NULL);
   1360 		if (error)
   1361 		    return error;
   1362 
   1363 		if (cmd == DIOCWDINFO)
   1364 		    error = writedisklabel(dev, fdstrategy, &buffer, NULL);
   1365 		return error;
   1366 
   1367 	case FDIOCGETFORMAT:
   1368 		form_parms = (struct fdformat_parms *)addr;
   1369 		form_parms->fdformat_version = FDFORMAT_VERSION;
   1370 		form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
   1371 		form_parms->ncyl = fd->sc_type->tracks;
   1372 		form_parms->nspt = fd->sc_type->sectrac;
   1373 		form_parms->ntrk = fd->sc_type->heads;
   1374 		form_parms->stepspercyl = fd->sc_type->step;
   1375 		form_parms->gaplen = fd->sc_type->gap2;
   1376 		form_parms->fillbyte = fd->sc_type->fillbyte;
   1377 		form_parms->interleave = fd->sc_type->interleave;
   1378 		switch (fd->sc_type->rate) {
   1379 		case FDC_500KBPS:
   1380 			form_parms->xfer_rate = 500 * 1024;
   1381 			break;
   1382 		case FDC_300KBPS:
   1383 			form_parms->xfer_rate = 300 * 1024;
   1384 			break;
   1385 		case FDC_250KBPS:
   1386 			form_parms->xfer_rate = 250 * 1024;
   1387 			break;
   1388 		case FDC_125KBPS:
   1389 			form_parms->xfer_rate = 125 * 1024;
   1390 			break;
   1391 		default:
   1392 			return EINVAL;
   1393 		}
   1394 		return 0;
   1395 
   1396 	case FDIOCSETFORMAT:
   1397 		if((flag & FWRITE) == 0)
   1398 			return EBADF;	/* must be opened for writing */
   1399 		form_parms = (struct fdformat_parms *)addr;
   1400 		if (form_parms->fdformat_version != FDFORMAT_VERSION)
   1401 			return EINVAL;	/* wrong version of formatting prog */
   1402 
   1403 		scratch = form_parms->nbps >> 7;
   1404 		if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
   1405 		    scratch & ~(1 << (ffs(scratch)-1)))
   1406 			/* not a power-of-two multiple of 128 */
   1407 			return EINVAL;
   1408 
   1409 		switch (form_parms->xfer_rate) {
   1410 		case 500 * 1024:
   1411 			fd->sc_type->rate = FDC_500KBPS;
   1412 			break;
   1413 		case 300 * 1024:
   1414 			fd->sc_type->rate = FDC_300KBPS;
   1415 			break;
   1416 		case 250 * 1024:
   1417 			fd->sc_type->rate = FDC_250KBPS;
   1418 			break;
   1419 		case 125 * 1024:
   1420 			fd->sc_type->rate = FDC_125KBPS;
   1421 			break;
   1422 		default:
   1423 			return EINVAL;
   1424 		}
   1425 
   1426 		if (form_parms->nspt > FD_MAX_NSEC ||
   1427 		    form_parms->fillbyte > 0xff ||
   1428 		    form_parms->interleave > 0xff)
   1429 			return EINVAL;
   1430 		fd->sc_type->sectrac = form_parms->nspt;
   1431 		if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
   1432 			return EINVAL;
   1433 		fd->sc_type->heads = form_parms->ntrk;
   1434 		fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
   1435 		fd->sc_type->secsize = ffs(scratch)-1;
   1436 		fd->sc_type->gap2 = form_parms->gaplen;
   1437 		fd->sc_type->tracks = form_parms->ncyl;
   1438 		fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
   1439 			form_parms->nbps / DEV_BSIZE;
   1440 		fd->sc_type->step = form_parms->stepspercyl;
   1441 		fd->sc_type->fillbyte = form_parms->fillbyte;
   1442 		fd->sc_type->interleave = form_parms->interleave;
   1443 		return 0;
   1444 
   1445 	case FDIOCFORMAT_TRACK:
   1446 		if((flag & FWRITE) == 0)
   1447 			return EBADF;	/* must be opened for writing */
   1448 		form_cmd = (struct fdformat_cmd *)addr;
   1449 		if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
   1450 			return EINVAL;	/* wrong version of formatting prog */
   1451 
   1452 		if (form_cmd->head >= fd->sc_type->heads ||
   1453 		    form_cmd->cylinder >= fd->sc_type->tracks) {
   1454 			return EINVAL;
   1455 		}
   1456 
   1457 		fd_formb.head = form_cmd->head;
   1458 		fd_formb.cyl = form_cmd->cylinder;
   1459 		fd_formb.transfer_rate = fd->sc_type->rate;
   1460 		fd_formb.fd_formb_secshift = fd->sc_type->secsize;
   1461 		fd_formb.fd_formb_nsecs = fd->sc_type->sectrac;
   1462 		fd_formb.fd_formb_gaplen = fd->sc_type->gap2;
   1463 		fd_formb.fd_formb_fillbyte = fd->sc_type->fillbyte;
   1464 
   1465 		bzero(il,sizeof il);
   1466 		for (j = 0, i = 1; i <= fd_formb.fd_formb_nsecs; i++) {
   1467 			while (il[(j%fd_formb.fd_formb_nsecs)+1])
   1468 				j++;
   1469 			il[(j%fd_formb.fd_formb_nsecs)+1] = i;
   1470 			j += fd->sc_type->interleave;
   1471 		}
   1472 		for (i = 0; i < fd_formb.fd_formb_nsecs; i++) {
   1473 			fd_formb.fd_formb_cylno(i) = form_cmd->cylinder;
   1474 			fd_formb.fd_formb_headno(i) = form_cmd->head;
   1475 			fd_formb.fd_formb_secno(i) = il[i+1];
   1476 			fd_formb.fd_formb_secsize(i) = fd->sc_type->secsize;
   1477 		}
   1478 
   1479 		error = fdformat(dev, &fd_formb, p);
   1480 		return error;
   1481 
   1482 	case FDIOCGETOPTS:		/* get drive options */
   1483 		*(int *)addr = fd->sc_opts;
   1484 		return 0;
   1485 
   1486 	case FDIOCSETOPTS:		/* set drive options */
   1487 		fd->sc_opts = *(int *)addr;
   1488 		return 0;
   1489 
   1490 
   1491 	default:
   1492 		return ENOTTY;
   1493 	}
   1494 
   1495 #ifdef DIAGNOSTIC
   1496 	panic("fdioctl: impossible");
   1497 #endif
   1498 }
   1499 
   1500 int
   1501 fdformat(dev, finfo, p)
   1502 	dev_t dev;
   1503 	struct ne7_fd_formb *finfo;
   1504 	struct proc *p;
   1505 {
   1506 	int rv = 0, s;
   1507 	struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(dev)];
   1508 	struct fd_type *type = fd->sc_type;
   1509 	struct buf *bp;
   1510 
   1511 	/* set up a buffer header for fdstrategy() */
   1512 	bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
   1513 	if(bp == 0)
   1514 		return ENOBUFS;
   1515 	PHOLD(p);
   1516 	bzero((void *)bp, sizeof(struct buf));
   1517 	bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
   1518 	bp->b_proc = p;
   1519 	bp->b_dev = dev;
   1520 
   1521 	/*
   1522 	 * calculate a fake blkno, so fdstrategy() would initiate a
   1523 	 * seek to the requested cylinder
   1524 	 */
   1525 	bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
   1526 		       + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
   1527 
   1528 	bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
   1529 	bp->b_data = (caddr_t)finfo;
   1530 
   1531 #ifdef DEBUG
   1532 	printf("fdformat: blkno %x count %lx\n", bp->b_blkno, bp->b_bcount);
   1533 #endif
   1534 
   1535 	/* now do the format */
   1536 	fdstrategy(bp);
   1537 
   1538 	/* ...and wait for it to complete */
   1539 	s = splbio();
   1540 	while(!(bp->b_flags & B_DONE)) {
   1541 		rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
   1542 		if (rv == EWOULDBLOCK)
   1543 			break;
   1544 	}
   1545 	splx(s);
   1546 
   1547 	if (rv == EWOULDBLOCK) {
   1548 		/* timed out */
   1549 		rv = EIO;
   1550 		biodone(bp);
   1551 	}
   1552 	if(bp->b_flags & B_ERROR) {
   1553 		rv = bp->b_error;
   1554 	}
   1555 	PRELE(p);
   1556 	free(bp, M_TEMP);
   1557 	return rv;
   1558 }
   1559 
   1560 
   1561 /*
   1562  * Obtain a disklabel. Either a real one from the disk or, if there
   1563  * is none, a fake one.
   1564  */
   1565 static void
   1566 fdgetdisklabel(fd, dev)
   1567 struct fd_softc *fd;
   1568 dev_t		dev;
   1569 {
   1570 	struct disklabel	*lp;
   1571 	struct cpu_disklabel	cpulab;
   1572 
   1573 	if (fd->sc_flags & FD_HAVELAB)
   1574 		return; /* Already got one */
   1575 
   1576 	lp   = fd->sc_dk.dk_label;
   1577 
   1578 	bzero(lp, sizeof(*lp));
   1579 	bzero(&cpulab, sizeof(cpulab));
   1580 
   1581 	lp->d_secpercyl  = fd->sc_type->seccyl;
   1582 	lp->d_type       = DTYPE_FLOPPY;
   1583 	lp->d_secsize    = FDC_BSIZE;
   1584 	lp->d_secperunit = fd->sc_type->size;
   1585 
   1586 	/*
   1587 	 * If there is no label on the disk: fake one
   1588 	 */
   1589 	if (readdisklabel(dev, fdstrategy, lp, &cpulab) != NULL)
   1590 		fdgetdefaultlabel(fd, lp, RAW_PART);
   1591 	fd->sc_flags |= FD_HAVELAB;
   1592 
   1593 	if ((FDC_BSIZE * fd->sc_type->size)
   1594 		< (lp->d_secsize * lp->d_secperunit)) {
   1595 		/*
   1596 		 * XXX: Ignore these fields. If you drop a vnddisk
   1597 		 *	on more than one floppy, you'll get disturbing
   1598 		 *	sounds!
   1599 		 */
   1600 		lp->d_secpercyl  = fd->sc_type->seccyl;
   1601 		lp->d_type       = DTYPE_FLOPPY;
   1602 		lp->d_secsize    = FDC_BSIZE;
   1603 		lp->d_secperunit = fd->sc_type->size;
   1604 	}
   1605 }
   1606 
   1607 /*
   1608  * Build defaultdisk label. For now we only create a label from what we
   1609  * know from 'sc'.
   1610  */
   1611 static void
   1612 fdgetdefaultlabel(fd, lp, part)
   1613 	struct fd_softc  *fd;
   1614 	struct disklabel *lp;
   1615 	int part;
   1616 {
   1617 	bzero(lp, sizeof(struct disklabel));
   1618 
   1619 	lp->d_secsize     = 128 * (1 << fd->sc_type->secsize);
   1620 	lp->d_ntracks     = fd->sc_type->heads;
   1621 	lp->d_nsectors    = fd->sc_type->sectrac;
   1622 	lp->d_secpercyl   = lp->d_ntracks * lp->d_nsectors;
   1623 	lp->d_ncylinders  = fd->sc_type->size / lp->d_secpercyl;
   1624 	lp->d_secperunit  = fd->sc_type->size;
   1625 
   1626 	lp->d_type        = DTYPE_FLOPPY;
   1627 	lp->d_rpm         = 300; 	/* good guess I suppose.	*/
   1628 	lp->d_interleave  = 1;		/* FIXME: is this OK?		*/
   1629 	lp->d_bbsize      = 0;
   1630 	lp->d_sbsize      = 0;
   1631 	lp->d_npartitions = part + 1;
   1632 	lp->d_trkseek     = 6000; 	/* Who cares...			*/
   1633 	lp->d_magic       = DISKMAGIC;
   1634 	lp->d_magic2      = DISKMAGIC;
   1635 	lp->d_checksum    = dkcksum(lp);
   1636 	lp->d_partitions[part].p_size   = lp->d_secperunit;
   1637 	lp->d_partitions[part].p_fstype = FS_UNUSED;
   1638 	lp->d_partitions[part].p_fsize  = 1024;
   1639 	lp->d_partitions[part].p_frag   = 8;
   1640 }
   1641