Home | History | Annotate | Line # | Download | only in mainbus
fd.c revision 1.49
      1 /*	$NetBSD: fd.c,v 1.49 2010/12/09 05:14:28 uebayasi 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.49 2010/12/09 05:14:28 uebayasi 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 =
    599 		    device_private(device_parent(&fd->sc_dev));
    600 		if (fdc->sc_state == DEVIDLE) {
    601 			printf("fdstrategy: controller inactive\n");
    602 			fdcstart(fdc);
    603 		}
    604 	}
    605 #endif
    606 	splx(s);
    607 	return;
    608 
    609 done:
    610 	/* Toss transfer; we're done early. */
    611 	bp->b_resid = bp->b_bcount;
    612 	biodone(bp);
    613 }
    614 
    615 void
    616 fdstart(struct fd_softc *fd)
    617 {
    618 	struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
    619 	int active = fdc->sc_drives.tqh_first != 0;
    620 
    621 	/* Link into controller queue. */
    622 	fd->sc_active = 1;
    623 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    624 
    625 	/* If controller not already active, start it. */
    626 	if (!active)
    627 		fdcstart(fdc);
    628 }
    629 
    630 void
    631 fdfinish(struct fd_softc *fd, struct buf *bp)
    632 {
    633 	struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
    634 
    635 	/*
    636 	 * Move this drive to the end of the queue to give others a `fair'
    637 	 * chance.  We only force a switch if N operations are completed while
    638 	 * another drive is waiting to be serviced, since there is a long motor
    639 	 * startup delay whenever we switch.
    640 	 */
    641 	(void)bufq_get(fd->sc_q);
    642 	if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
    643 		fd->sc_ops = 0;
    644 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
    645 		if (bufq_peek(fd->sc_q) != NULL)
    646 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    647 		else
    648 			fd->sc_active = 0;
    649 	}
    650 	bp->b_resid = fd->sc_bcount;
    651 	fd->sc_skip = 0;
    652 
    653 	biodone(bp);
    654 	/* turn off motor 5s from now */
    655 	callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
    656 	fdc->sc_state = DEVIDLE;
    657 }
    658 
    659 int
    660 fdread(dev_t dev, struct uio *uio, int flags)
    661 {
    662 
    663 	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
    664 }
    665 
    666 int
    667 fdwrite(dev_t dev, struct uio *uio, int flags)
    668 {
    669 
    670 	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
    671 }
    672 
    673 void
    674 fd_set_motor(struct fdc_softc *fdc, int reset)
    675 {
    676 	struct fd_softc *fd;
    677 	u_char status;
    678 	int n;
    679 
    680 	if ((fd = fdc->sc_drives.tqh_first) != NULL)
    681 		status = fd->sc_drive;
    682 	else
    683 		status = 0;
    684 	if (!reset)
    685 		status |= FDO_FRST | FDO_FDMAEN;
    686 	for (n = 0; n < 4; n++)
    687 		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
    688 			status |= FDO_MOEN(n);
    689 	bus_space_write_2(fdc->sc_iot, fdc->sc_ioh, fdout, status);
    690 }
    691 
    692 void
    693 fd_motor_off(void *arg)
    694 {
    695 	struct fd_softc *fd = arg;
    696 	int s;
    697 
    698 	s = splbio();
    699 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
    700 	fd_set_motor((struct fdc_softc *) device_parent(&fd->sc_dev), 0);
    701 	splx(s);
    702 }
    703 
    704 void
    705 fd_motor_on(void *arg)
    706 {
    707 	struct fd_softc *fd = arg;
    708 	struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
    709 	int s;
    710 
    711 	s = splbio();
    712 	fd->sc_flags &= ~FD_MOTOR_WAIT;
    713 	if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
    714 		(void) fdcintr(fdc);
    715 	splx(s);
    716 }
    717 
    718 int
    719 fdcresult(struct fdc_softc *fdc)
    720 {
    721 	bus_space_tag_t iot = fdc->sc_iot;
    722 	bus_space_handle_t ioh = fdc->sc_ioh;
    723 	u_char i;
    724 	int j = 100000,
    725 	    n = 0;
    726 
    727 	for (; j; j--) {
    728 		i = bus_space_read_1(iot, ioh, fdsts) &
    729 		    (NE7_DIO | NE7_RQM | NE7_CB);
    730 		if (i == NE7_RQM)
    731 			return n;
    732 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
    733 			if (n >= sizeof(fdc->sc_status)) {
    734 				log(LOG_ERR, "fdcresult: overrun\n");
    735 				return -1;
    736 			}
    737 			fdc->sc_status[n++] =
    738 			    bus_space_read_1(iot, ioh, fddata);
    739 		}
    740 		delay(10);
    741 	}
    742 	log(LOG_ERR, "fdcresult: timeout\n");
    743 	return -1;
    744 }
    745 
    746 int
    747 out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x)
    748 {
    749 	int i = 100000;
    750 
    751 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
    752 	if (i <= 0)
    753 		return -1;
    754 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
    755 	if (i <= 0)
    756 		return -1;
    757 	bus_space_write_2(iot, ioh, fddata, x);
    758 	return 0;
    759 }
    760 
    761 int
    762 fdopen(dev_t dev, int flags, int mode, struct lwp *l)
    763 {
    764 	struct fd_softc *fd;
    765 	struct fd_type *type;
    766 
    767 	fd = device_lookup_private(&fd_cd, FDUNIT(dev));
    768 	if (fd == NULL)
    769 		return ENXIO;
    770 	type = fd_dev_to_type(fd, dev);
    771 	if (type == NULL)
    772 		return ENXIO;
    773 
    774 	if ((fd->sc_flags & FD_OPEN) != 0 &&
    775 	    memcmp(fd->sc_type, type, sizeof(*type)))
    776 		return EBUSY;
    777 
    778 	fd->sc_type_copy = *type;
    779 	fd->sc_type = &fd->sc_type_copy;
    780 	fd->sc_cylin = -1;
    781 	fd->sc_flags |= FD_OPEN;
    782 
    783 	return 0;
    784 }
    785 
    786 int
    787 fdclose(dev_t dev, int flags, int mode, struct lwp *l)
    788 {
    789 	struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
    790 
    791 	fd->sc_flags &= ~FD_OPEN;
    792 	fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT);
    793 	return 0;
    794 }
    795 
    796 void
    797 fdcstart(struct fdc_softc *fdc)
    798 {
    799 
    800 #ifdef DIAGNOSTIC
    801 	/* only got here if controller's drive queue was inactive; should
    802 	   be in idle state */
    803 	if (fdc->sc_state != DEVIDLE) {
    804 		printf("fdcstart: not idle\n");
    805 		return;
    806 	}
    807 #endif
    808 	(void) fdcintr(fdc);
    809 }
    810 
    811 static void
    812 fdcpstatus(int n, struct fdc_softc *fdc)
    813 {
    814 	char bits[64];
    815 
    816 	switch (n) {
    817 	case 0:
    818 		printf("\n");
    819 		break;
    820 	case 2:
    821 		snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]);
    822 		printf(" (st0 %s cyl %d)\n", bits, fdc->sc_status[1]);
    823 		break;
    824 	case 7:
    825 		snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]);
    826 		printf(" (st0 %s", bits);
    827 		snprintb(bits, sizeof(bits), NE7_ST1BITS, fdc->sc_status[1]);
    828 		printf(" st1 %s", bits);
    829 		snprintb(bits, sizeof(bits), NE7_ST2BITS, fdc->sc_status[2]);
    830 		printf(" st2 %s", bits);
    831 		printf(" cyl %d head %d sec %d)\n",
    832 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
    833 		break;
    834 #ifdef DIAGNOSTIC
    835 	default:
    836 		printf("\nfdcstatus: weird size");
    837 		break;
    838 #endif
    839 	}
    840 }
    841 
    842 void
    843 fdcstatus(struct device *dv, int n, const char *s)
    844 {
    845 	struct fdc_softc *fdc = (void *) device_parent(dv);
    846 
    847 	if (n == 0) {
    848 		out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
    849 		(void) fdcresult(fdc);
    850 		n = 2;
    851 	}
    852 
    853 	printf("%s: %s", device_xname(dv), s);
    854 	fdcpstatus(n, fdc);
    855 }
    856 
    857 void
    858 fdctimeout(void *arg)
    859 {
    860 	struct fdc_softc *fdc = arg;
    861 	struct fd_softc *fd = fdc->sc_drives.tqh_first;
    862 	int s;
    863 
    864 	s = splbio();
    865 #ifdef DEBUG
    866 	log(LOG_ERR,"fdctimeout: state %d\n", fdc->sc_state);
    867 #endif
    868 	fdcstatus(&fd->sc_dev, 0, "timeout");
    869 
    870 	if (bufq_peek(fd->sc_q) != NULL)
    871 		fdc->sc_state++;
    872 	else
    873 		fdc->sc_state = DEVIDLE;
    874 
    875 	(void) fdcintr(fdc);
    876 	splx(s);
    877 }
    878 
    879 void
    880 fdcpseudointr(void *arg)
    881 {
    882 	int s;
    883 
    884 	/* Just ensure it has the right spl. */
    885 	s = splbio();
    886 	(void) fdcintr(arg);
    887 	splx(s);
    888 }
    889 
    890 int
    891 fdcintr(void *arg)
    892 {
    893 	struct fdc_softc *fdc = arg;
    894 #define	st0	fdc->sc_status[0]
    895 #define	cyl	fdc->sc_status[1]
    896 	struct fd_softc *fd;
    897 	struct buf *bp;
    898 	bus_space_tag_t iot = fdc->sc_iot;
    899 	bus_space_handle_t ioh = fdc->sc_ioh;
    900 	int read, head, sec, i, nblks;
    901 	struct fd_type *type;
    902 	struct ne7_fd_formb *finfo = NULL;
    903 
    904 loop:
    905 	/* Is there a drive for the controller to do a transfer with? */
    906 	fd = fdc->sc_drives.tqh_first;
    907 	if (fd == NULL) {
    908 		fdc->sc_state = DEVIDLE;
    909  		return 1;
    910 	}
    911 
    912 	/* Is there a transfer to this drive?  If not, deactivate drive. */
    913 	bp = bufq_peek(fd->sc_q);
    914 	if (bp == NULL) {
    915 		fd->sc_ops = 0;
    916 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
    917 		fd->sc_active = 0;
    918 		goto loop;
    919 	}
    920 
    921 	if (bp->b_flags & B_FORMAT)
    922 		finfo = (struct ne7_fd_formb *)bp->b_data;
    923 
    924 	switch (fdc->sc_state) {
    925 	case DEVIDLE:
    926 		fdc->sc_errors = 0;
    927 		fd->sc_skip = 0;
    928 		fd->sc_bcount = bp->b_bcount;
    929 		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
    930 		callout_stop(&fd->sc_motoroff_ch);
    931 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
    932 			fdc->sc_state = MOTORWAIT;
    933 			return 1;
    934 		}
    935 		if ((fd->sc_flags & FD_MOTOR) == 0) {
    936 			/* Turn on the motor, being careful about pairing. */
    937 			struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
    938 			if (ofd && ofd->sc_flags & FD_MOTOR) {
    939 				callout_stop(&ofd->sc_motoroff_ch);
    940 				ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
    941 			}
    942 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
    943 			fd_set_motor(fdc, 0);
    944 			fdc->sc_state = MOTORWAIT;
    945 			/* Allow .25s for motor to stabilize. */
    946 			callout_reset(&fd->sc_motoron_ch, hz / 4,
    947 			    fd_motor_on, fd);
    948 			return 1;
    949 		}
    950 		/* Make sure the right drive is selected. */
    951 		fd_set_motor(fdc, 0);
    952 
    953 		/* fall through */
    954 	case DOSEEK:
    955 	doseek:
    956 		if (fd->sc_cylin == bp->b_cylinder)
    957 			goto doio;
    958 
    959 #if 1
    960 		out_fdc(iot, ioh, NE7CMD_CONFIGURE);/* configure command */
    961 		out_fdc(iot, ioh, 0);
    962 		out_fdc(iot, ioh, 0x18);
    963 		out_fdc(iot, ioh, 0);
    964 #endif
    965 		out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
    966 		out_fdc(iot, ioh, fd->sc_type->steprate);
    967 		out_fdc(iot, ioh, 6);		/* XXX head load time == 6ms */
    968 
    969 		out_fdc(iot, ioh, NE7CMD_SEEK);	/* seek function */
    970 		out_fdc(iot, ioh, fd->sc_drive);	/* drive number */
    971 		out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
    972 
    973 		fd->sc_cylin = -1;
    974 		fdc->sc_state = SEEKWAIT;
    975 
    976 		iostat_seek(fd->sc_dk.dk_stats);
    977 		disk_busy(&fd->sc_dk);
    978 
    979 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
    980 		return 1;
    981 
    982 	case DOIO:
    983 	doio:
    984 		type = fd->sc_type;
    985 		if (finfo)
    986 			fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
    987 				      (char *)finfo;
    988 		sec = fd->sc_blkno % type->seccyl;
    989 		nblks = type->seccyl - sec;
    990 		nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
    991 		nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
    992 		fd->sc_nblks = nblks;
    993 		fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
    994 		head = sec / type->sectrac;
    995 		sec -= head * type->sectrac;
    996 #ifdef DIAGNOSTIC
    997 		{daddr_t  block;
    998 		 block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec;
    999 		 if (block != fd->sc_blkno) {
   1000 			 printf("fdcintr: block %" PRId64
   1001 			     " != blkno %" PRId64 "\n",
   1002 				block, fd->sc_blkno);
   1003 #ifdef DDB
   1004 			 Debugger();
   1005 #endif
   1006 		 }}
   1007 #endif
   1008 		read = bp->b_flags & B_READ;
   1009 		if (read) {
   1010 			fdc->sc_fh.fh_func = floppy_read_fiq;
   1011 			fdc->sc_fh.fh_size = floppy_read_fiq_end -
   1012 			    floppy_read_fiq;
   1013 		} else {
   1014 			fdc->sc_fh.fh_func = floppy_write_fiq;
   1015 			fdc->sc_fh.fh_size = floppy_read_fiq_end -
   1016 			    floppy_read_fiq;
   1017 		}
   1018 		fdc->sc_fh.fh_flags = 0;
   1019 		fdc->sc_fh.fh_regs = &fdc->sc_fr;
   1020 		fdc->sc_fr.fr_r9 = IOMD_BASE + (IOMD_FIQRQ << 2);
   1021 		fdc->sc_fr.fr_r10 = fd->sc_nbytes;
   1022 		fdc->sc_fr.fr_r11 =
   1023 		    (u_int)((uintptr_t)bp->b_data + fd->sc_skip);
   1024 		fdc->sc_fr.fr_r12 = fdc->sc_drq;
   1025 #ifdef FD_DEBUG
   1026 		printf("fdc-doio:r9=%x r10=%x r11=%x r12=%x data=%x skip=%x\n",
   1027 		    fdc->sc_fr.fr_r9, fdc->sc_fr.fh_r10, fdc->sc_fr.fh_r11,
   1028 		    fdc->sc_fr.fh_r12, (u_int)bp->b_data, fd->sc_skip);
   1029 #endif
   1030 		if (fiq_claim(&fdc->sc_fh) == -1)
   1031 			panic("%s: Cannot claim FIQ vector", fdc->sc_dev.dv_xname);
   1032 		IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x01);
   1033 		bus_space_write_2(iot, ioh, fdctl, type->rate);
   1034 #ifdef FD_DEBUG
   1035 		printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
   1036 			read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
   1037 			head, sec, nblks);
   1038 #endif
   1039 		if (finfo) {
   1040 			/* formatting */
   1041 			if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) {
   1042 				fdc->sc_errors = 4;
   1043 				fdcretry(fdc);
   1044 				goto loop;
   1045 			}
   1046 			out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1047 			out_fdc(iot, ioh, finfo->fd_formb_secshift);
   1048 			out_fdc(iot, ioh, finfo->fd_formb_nsecs);
   1049 			out_fdc(iot, ioh, finfo->fd_formb_gaplen);
   1050 			out_fdc(iot, ioh, finfo->fd_formb_fillbyte);
   1051 		} else {
   1052 			if (read)
   1053 				out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
   1054 			else
   1055 				out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
   1056 			out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1057 			out_fdc(iot, ioh, fd->sc_cylin); /* track */
   1058 			out_fdc(iot, ioh, head);
   1059 			out_fdc(iot, ioh, sec + 1);	 /* sector +1 */
   1060 			out_fdc(iot, ioh, type->secsize);/* sector size */
   1061 			out_fdc(iot, ioh, type->sectrac);/* sectors/track */
   1062 			out_fdc(iot, ioh, type->gap1);	 /* gap1 size */
   1063 			out_fdc(iot, ioh, type->datalen);/* data length */
   1064 		}
   1065 		fdc->sc_state = IOCOMPLETE;
   1066 
   1067 		disk_busy(&fd->sc_dk);
   1068 
   1069 		/* allow 2 seconds for operation */
   1070 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1071 		return 1;				/* will return later */
   1072 
   1073 	case SEEKWAIT:
   1074 		callout_stop(&fdc->sc_timo_ch);
   1075 		fdc->sc_state = SEEKCOMPLETE;
   1076 		/* allow 1/50 second for heads to settle */
   1077 #if 0
   1078 		callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
   1079 #endif
   1080 		return 1;
   1081 
   1082 	case SEEKCOMPLETE:
   1083 		/* no data on seek */
   1084 		disk_unbusy(&fd->sc_dk, 0, 0);
   1085 
   1086 		/* Make sure seek really happened. */
   1087 		out_fdc(iot, ioh, NE7CMD_SENSEI);
   1088 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
   1089 		    cyl != bp->b_cylinder * fd->sc_type->step) {
   1090 #ifdef FD_DEBUG
   1091 			fdcstatus(&fd->sc_dev, 2, "seek failed");
   1092 #endif
   1093 			fdcretry(fdc);
   1094 			goto loop;
   1095 		}
   1096 		fd->sc_cylin = bp->b_cylinder;
   1097 		goto doio;
   1098 
   1099 	case IOTIMEDOUT:
   1100 		fiq_release(&fdc->sc_fh);
   1101 		IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
   1102 	case SEEKTIMEDOUT:
   1103 	case RECALTIMEDOUT:
   1104 	case RESETTIMEDOUT:
   1105 		fdcretry(fdc);
   1106 		goto loop;
   1107 
   1108 	case IOCOMPLETE: /* IO DONE, post-analyze */
   1109 		callout_stop(&fdc->sc_timo_ch);
   1110 
   1111 		disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
   1112 		    (bp->b_flags & B_READ));
   1113 
   1114 		if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) {
   1115 			fiq_release(&fdc->sc_fh);
   1116 			IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
   1117 #ifdef FD_DEBUG
   1118 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
   1119 			    "read failed" : "write failed");
   1120 			printf("blkno %d nblks %d\n",
   1121 			    fd->sc_blkno, fd->sc_nblks);
   1122 #endif
   1123 			fdcretry(fdc);
   1124 			goto loop;
   1125 		}
   1126 		fiq_release(&fdc->sc_fh);
   1127 		IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
   1128 		if (fdc->sc_errors) {
   1129 #if 0
   1130 			diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
   1131 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
   1132 			printf("\n");
   1133 #endif
   1134 			fdc->sc_errors = 0;
   1135 		}
   1136 		fd->sc_blkno += fd->sc_nblks;
   1137 		fd->sc_skip += fd->sc_nbytes;
   1138 		fd->sc_bcount -= fd->sc_nbytes;
   1139 		if (!finfo && fd->sc_bcount > 0) {
   1140 			bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
   1141 			goto doseek;
   1142 		}
   1143 		fdfinish(fd, bp);
   1144 		goto loop;
   1145 
   1146 	case DORESET:
   1147 		/* try a reset, keep motor on */
   1148 		fd_set_motor(fdc, 1);
   1149 		delay(100);
   1150 		fd_set_motor(fdc, 0);
   1151 		fdc->sc_state = RESETCOMPLETE;
   1152 		callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
   1153 		return 1;			/* will return later */
   1154 
   1155 	case RESETCOMPLETE:
   1156 		callout_stop(&fdc->sc_timo_ch);
   1157 		/* clear the controller output buffer */
   1158 		for (i = 0; i < 4; i++) {
   1159 			out_fdc(iot, ioh, NE7CMD_SENSEI);
   1160 			(void) fdcresult(fdc);
   1161 		}
   1162 
   1163 		/* fall through */
   1164 	case DORECAL:
   1165 		out_fdc(iot, ioh, NE7CMD_RECAL);	/* recalibrate function */
   1166 		out_fdc(iot, ioh, fd->sc_drive);
   1167 		fdc->sc_state = RECALWAIT;
   1168 		callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
   1169 		return 1;			/* will return later */
   1170 
   1171 	case RECALWAIT:
   1172 		callout_stop(&fdc->sc_timo_ch);
   1173 		fdc->sc_state = RECALCOMPLETE;
   1174 		/* allow 1/30 second for heads to settle */
   1175 #if 0
   1176 		callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
   1177 #endif
   1178 		return 1;			/* will return later */
   1179 
   1180 	case RECALCOMPLETE:
   1181 		out_fdc(iot, ioh, NE7CMD_SENSEI);
   1182 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
   1183 #ifdef FD_DEBUG
   1184 			fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
   1185 #endif
   1186 			fdcretry(fdc);
   1187 			goto loop;
   1188 		}
   1189 		fd->sc_cylin = 0;
   1190 		goto doseek;
   1191 
   1192 	case MOTORWAIT:
   1193 		if (fd->sc_flags & FD_MOTOR_WAIT)
   1194 			return 1;		/* time's not up yet */
   1195 		goto doseek;
   1196 
   1197 	default:
   1198 		fdcstatus(&fd->sc_dev, 0, "stray interrupt");
   1199 		return 1;
   1200 	}
   1201 #ifdef DIAGNOSTIC
   1202 	panic("fdcintr: impossible");
   1203 #endif
   1204 #undef	st0
   1205 #undef	cyl
   1206 }
   1207 
   1208 void
   1209 fdcretry(struct fdc_softc *fdc)
   1210 {
   1211 	struct fd_softc *fd;
   1212 	struct buf *bp;
   1213 
   1214 	fd = fdc->sc_drives.tqh_first;
   1215 	bp = bufq_peek(fd->sc_q);
   1216 
   1217 	if (fd->sc_opts & FDOPT_NORETRY)
   1218 	    goto fail;
   1219 	switch (fdc->sc_errors) {
   1220 	case 0:
   1221 		/* try again */
   1222 		fdc->sc_state = DOSEEK;
   1223 		break;
   1224 
   1225 	case 1: case 2: case 3:
   1226 		/* didn't work; try recalibrating */
   1227 		fdc->sc_state = DORECAL;
   1228 		break;
   1229 
   1230 	case 4:
   1231 		/* still no go; reset the bastard */
   1232 		fdc->sc_state = DORESET;
   1233 		break;
   1234 
   1235 	default:
   1236 	fail:
   1237 		if ((fd->sc_opts & FDOPT_SILENT) == 0) {
   1238 			diskerr(bp, "fd", "hard error", LOG_PRINTF,
   1239 				fd->sc_skip / FDC_BSIZE,
   1240 				(struct disklabel *)NULL);
   1241 			fdcpstatus(7, fdc);
   1242 		}
   1243 
   1244 		bp->b_error = EIO;
   1245 		fdfinish(fd, bp);
   1246 	}
   1247 	fdc->sc_errors++;
   1248 }
   1249 
   1250 int
   1251 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
   1252 {
   1253 	struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
   1254 	struct fdformat_parms *form_parms;
   1255 	struct fdformat_cmd *form_cmd;
   1256 	struct ne7_fd_formb *fd_formb;
   1257 	struct disklabel buffer;
   1258 	int error;
   1259 	unsigned int scratch;
   1260 	int il[FD_MAX_NSEC + 1];
   1261 	register int i, j;
   1262 
   1263 	switch (cmd) {
   1264 	case DIOCGDINFO:
   1265 		memset(&buffer, 0, sizeof(buffer));
   1266 
   1267 		buffer.d_secpercyl = fd->sc_type->seccyl;
   1268 		buffer.d_type = DTYPE_FLOPPY;
   1269 		buffer.d_secsize = FDC_BSIZE;
   1270 
   1271 		if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
   1272 			return EINVAL;
   1273 
   1274 		*(struct disklabel *)addr = buffer;
   1275 		return 0;
   1276 
   1277 	case DIOCWLABEL:
   1278 		if ((flag & FWRITE) == 0)
   1279 			return EBADF;
   1280 		/* XXX do something */
   1281 		return 0;
   1282 
   1283 	case DIOCWDINFO:
   1284 		if ((flag & FWRITE) == 0)
   1285 			return EBADF;
   1286 
   1287 		error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
   1288 		if (error)
   1289 			return error;
   1290 
   1291 		error = writedisklabel(dev, fdstrategy, &buffer, NULL);
   1292 		return error;
   1293 
   1294 	case FDIOCGETFORMAT:
   1295 		form_parms = (struct fdformat_parms *)addr;
   1296 		form_parms->fdformat_version = FDFORMAT_VERSION;
   1297 		form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
   1298 		form_parms->ncyl = fd->sc_type->cyls;
   1299 		form_parms->nspt = fd->sc_type->sectrac;
   1300 		form_parms->ntrk = fd->sc_type->heads;
   1301 		form_parms->stepspercyl = fd->sc_type->step;
   1302 		form_parms->gaplen = fd->sc_type->gap2;
   1303 		form_parms->fillbyte = fd->sc_type->fillbyte;
   1304 		form_parms->interleave = fd->sc_type->interleave;
   1305 		switch (fd->sc_type->rate) {
   1306 		case FDC_500KBPS:
   1307 			form_parms->xfer_rate = 500 * 1024;
   1308 			break;
   1309 		case FDC_300KBPS:
   1310 			form_parms->xfer_rate = 300 * 1024;
   1311 			break;
   1312 		case FDC_250KBPS:
   1313 			form_parms->xfer_rate = 250 * 1024;
   1314 			break;
   1315 		default:
   1316 			return EINVAL;
   1317 		}
   1318 		return 0;
   1319 
   1320 	case FDIOCSETFORMAT:
   1321 		if((flag & FWRITE) == 0)
   1322 			return EBADF;	/* must be opened for writing */
   1323 		form_parms = (struct fdformat_parms *)addr;
   1324 		if (form_parms->fdformat_version != FDFORMAT_VERSION)
   1325 			return EINVAL;	/* wrong version of formatting prog */
   1326 
   1327 		scratch = form_parms->nbps >> 7;
   1328 		if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
   1329 		    scratch & ~(1 << (ffs(scratch)-1)))
   1330 			/* not a power-of-two multiple of 128 */
   1331 			return EINVAL;
   1332 
   1333 		switch (form_parms->xfer_rate) {
   1334 		case 500 * 1024:
   1335 			fd->sc_type->rate = FDC_500KBPS;
   1336 			break;
   1337 		case 300 * 1024:
   1338 			fd->sc_type->rate = FDC_300KBPS;
   1339 			break;
   1340 		case 250 * 1024:
   1341 			fd->sc_type->rate = FDC_250KBPS;
   1342 			break;
   1343 		default:
   1344 			return EINVAL;
   1345 		}
   1346 
   1347 		if (form_parms->nspt > FD_MAX_NSEC ||
   1348 		    form_parms->fillbyte > 0xff ||
   1349 		    form_parms->interleave > 0xff)
   1350 			return EINVAL;
   1351 		fd->sc_type->sectrac = form_parms->nspt;
   1352 		if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
   1353 			return EINVAL;
   1354 		fd->sc_type->heads = form_parms->ntrk;
   1355 		fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
   1356 		fd->sc_type->secsize = ffs(scratch)-1;
   1357 		fd->sc_type->gap2 = form_parms->gaplen;
   1358 		fd->sc_type->cyls = form_parms->ncyl;
   1359 		fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
   1360 			form_parms->nbps / DEV_BSIZE;
   1361 		fd->sc_type->step = form_parms->stepspercyl;
   1362 		fd->sc_type->fillbyte = form_parms->fillbyte;
   1363 		fd->sc_type->interleave = form_parms->interleave;
   1364 		return 0;
   1365 
   1366 	case FDIOCFORMAT_TRACK:
   1367 		if((flag & FWRITE) == 0)
   1368 			return EBADF;	/* must be opened for writing */
   1369 		form_cmd = (struct fdformat_cmd *)addr;
   1370 		if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
   1371 			return EINVAL;	/* wrong version of formatting prog */
   1372 
   1373 		if (form_cmd->head >= fd->sc_type->heads ||
   1374 		    form_cmd->cylinder >= fd->sc_type->cyls) {
   1375 			return EINVAL;
   1376 		}
   1377 
   1378 		fd_formb = malloc(sizeof(struct ne7_fd_formb),
   1379 		    M_TEMP, M_NOWAIT);
   1380 		if(fd_formb == 0)
   1381 			return ENOMEM;
   1382 
   1383 
   1384 		fd_formb->head = form_cmd->head;
   1385 		fd_formb->cyl = form_cmd->cylinder;
   1386 		fd_formb->transfer_rate = fd->sc_type->rate;
   1387 		fd_formb->fd_formb_secshift = fd->sc_type->secsize;
   1388 		fd_formb->fd_formb_nsecs = fd->sc_type->sectrac;
   1389 		fd_formb->fd_formb_gaplen = fd->sc_type->gap2;
   1390 		fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte;
   1391 
   1392 		memset(il, 0, sizeof il);
   1393 		for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) {
   1394 			while (il[(j%fd_formb->fd_formb_nsecs)+1])
   1395 				j++;
   1396 			il[(j%fd_formb->fd_formb_nsecs)+1] = i;
   1397 			j += fd->sc_type->interleave;
   1398 		}
   1399 		for (i = 0; i < fd_formb->fd_formb_nsecs; i++) {
   1400 			fd_formb->fd_formb_cylno(i) = form_cmd->cylinder;
   1401 			fd_formb->fd_formb_headno(i) = form_cmd->head;
   1402 			fd_formb->fd_formb_secno(i) = il[i+1];
   1403 			fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize;
   1404 		}
   1405 
   1406 		error = fdformat(dev, fd_formb, l);
   1407 		free(fd_formb, M_TEMP);
   1408 		return error;
   1409 
   1410 	case FDIOCGETOPTS:		/* get drive options */
   1411 		*(int *)addr = fd->sc_opts;
   1412 		return 0;
   1413 
   1414 	case FDIOCSETOPTS:		/* set drive options */
   1415 		fd->sc_opts = *(int *)addr;
   1416 		return 0;
   1417 
   1418 	default:
   1419 		return ENOTTY;
   1420 	}
   1421 
   1422 #ifdef DIAGNOSTIC
   1423 	panic("fdioctl: impossible");
   1424 #endif
   1425 }
   1426 
   1427 int
   1428 fdformat(dev_t dev, struct ne7_fd_formb *finfo, struct lwp *l)
   1429 {
   1430 	int rv = 0;
   1431 	struct fd_softc *fd = device_lookup_private(&fd_cd,FDUNIT(dev));
   1432 	struct fd_type *type = fd->sc_type;
   1433 	struct buf *bp;
   1434 
   1435 	/* set up a buffer header for fdstrategy() */
   1436 	bp = getiobuf(NULL, false);
   1437 	if(bp == 0)
   1438 		return ENOBUFS;
   1439 	bp->b_flags = B_PHYS | B_FORMAT;
   1440 	bp->b_cflags |= BC_BUSY;
   1441 	bp->b_proc = l->l_proc;
   1442 	bp->b_dev = dev;
   1443 
   1444 	/*
   1445 	 * calculate a fake blkno, so fdstrategy() would initiate a
   1446 	 * seek to the requested cylinder
   1447 	 */
   1448 	bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
   1449 		       + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
   1450 
   1451 	bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
   1452 	bp->b_data = (void *)finfo;
   1453 
   1454 #ifdef DEBUG
   1455 	printf("fdformat: blkno %llx count %x\n",
   1456 	    (unsigned long long)bp->b_blkno, bp->b_bcount);
   1457 #endif
   1458 
   1459 	/* now do the format */
   1460 	fdstrategy(bp);
   1461 
   1462 	/* ...and wait for it to complete */
   1463 	/* XXX very dodgy */
   1464 	mutex_enter(bp->b_objlock);
   1465 	while (!(bp->b_oflags & BO_DONE)) {
   1466 		rv = cv_timedwait(&bp->b_done, bp->b_objlock, 20 * hz);
   1467 		if (rv == EWOULDBLOCK)
   1468 			break;
   1469 	}
   1470 	mutex_exit(bp->b_objlock);
   1471 
   1472 	if (rv == EWOULDBLOCK) {
   1473 		/* timed out */
   1474 		rv = EIO;
   1475 		biodone(bp);
   1476 	} else if (bp->b_error != 0)
   1477 		rv = bp->b_error;
   1478 	putiobuf(bp);
   1479 	return rv;
   1480 }
   1481 
   1482 #include <dev/md.h>
   1483 
   1484 int load_memory_disc_from_floppy(struct md_conf *md, dev_t dev);
   1485 
   1486 int
   1487 load_memory_disc_from_floppy(struct md_conf *md, dev_t dev)
   1488 {
   1489 	struct buf *bp;
   1490 	int loop;
   1491 	int s;
   1492 	int type;
   1493 	int floppysize;
   1494 
   1495 	if (bdevsw_lookup(dev) != &fd_bdevsw)
   1496 		return(EINVAL);
   1497 
   1498 	if (md->md_type == MD_UNCONFIGURED || md->md_addr == 0)
   1499 		return(EBUSY);
   1500 
   1501 	type = FDTYPE(dev) - 1;
   1502 	if (type < 0) type = 0;
   1503 	floppysize = fd_types[type].size << (fd_types[type].secsize + 7);
   1504 
   1505 	if (md->md_size < floppysize) {
   1506 		printf("Memory disc is not big enough for floppy image\n");
   1507 		return(EINVAL);
   1508 	}
   1509 
   1510 /* We have the memory disk ! */
   1511 
   1512 	printf("Loading memory disc : %4dK ", 0);
   1513 
   1514 /* obtain a buffer */
   1515 
   1516 	bp = geteblk(fd_types[type].sectrac * DEV_BSIZE);
   1517 
   1518 /* request no partition relocation by driver on I/O operations */
   1519 
   1520 	bp->b_dev = dev;
   1521 
   1522 	s = splbio();
   1523 
   1524 	if (fdopen(bp->b_dev, 0, 0, curlwp) != 0) {
   1525 		brelse(bp, 0);
   1526 		printf("Cannot open floppy device\n");
   1527 			return(EINVAL);
   1528 	}
   1529 
   1530 	for (loop = 0;
   1531 	    loop < (floppysize / DEV_BSIZE / fd_types[type].sectrac);
   1532 	    ++loop) {
   1533 		printf("\x08\x08\x08\x08\x08\x08%4dK ",
   1534 		    loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
   1535 		bp->b_blkno = loop * fd_types[type].sectrac;
   1536 		bp->b_bcount = fd_types[type].sectrac * DEV_BSIZE;
   1537 		bp->b_flags |= B_READ;
   1538 		bp->b_error = 0;
   1539 		bp->b_resid = 0;
   1540 		fdstrategy(bp);
   1541 
   1542 		if (biowait(bp))
   1543 			panic("Cannot load floppy image");
   1544 
   1545 		memcpy((char *)md->md_addr + loop * fd_types[type].sectrac
   1546 		    * DEV_BSIZE, (void *)bp->b_data,
   1547 		    fd_types[type].sectrac * DEV_BSIZE);
   1548 	}
   1549 	printf("\x08\x08\x08\x08\x08\x08%4dK done\n",
   1550 	    loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
   1551 
   1552 	fdclose(bp->b_dev, 0, 0, curlwp);
   1553 
   1554 	brelse(bp, 0);
   1555 
   1556 	splx(s);
   1557 	return(0);
   1558 }
   1559