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