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