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