Home | History | Annotate | Line # | Download | only in mainbus
fd.c revision 1.40
      1 /*	$NetBSD: fd.c,v 1.40 2008/12/16 22:35:21 christos 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.40 2008/12/16 22:35:21 christos 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 __P((struct device *, struct cfdata *, void *));
    178 int fdprint __P((void *, const char *));
    179 void fdcattach __P((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 __P((struct device *, struct cfdata *, void *));
    253 void fdattach __P((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 __P((struct fd_softc *));
    280 int fd_get_parms __P((struct fd_softc *));
    281 void fdstart __P((struct fd_softc *));
    282 
    283 struct dkdriver fddkdriver = { fdstrategy };
    284 
    285 struct fd_type *fd_nvtotype __P((char *, int, int));
    286 void fd_set_motor __P((struct fdc_softc *fdc, int reset));
    287 void fd_motor_off __P((void *arg));
    288 void fd_motor_on __P((void *arg));
    289 int fdcresult __P((struct fdc_softc *fdc));
    290 int out_fdc __P((bus_space_tag_t iot, bus_space_handle_t ioh, u_char x));
    291 void fdcstart __P((struct fdc_softc *fdc));
    292 void fdcstatus __P((struct device *dv, int n, const char *s));
    293 void fdctimeout __P((void *arg));
    294 void fdcpseudointr __P((void *arg));
    295 int fdcintr __P((void *));
    296 void fdcretry __P((struct fdc_softc *fdc));
    297 void fdfinish __P((struct fd_softc *fd, struct buf *bp));
    298 inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
    299 int fdformat __P((dev_t, struct ne7_fd_formb *, struct lwp *));
    300 
    301 int
    302 fdcprobe(parent, cf, aux)
    303 	struct device *parent;
    304 	struct cfdata *cf;
    305 	void *aux;
    306 {
    307 	struct pioc_attach_args *pa = aux;
    308 	bus_space_tag_t iot;
    309 	bus_space_handle_t ioh;
    310 	int rv;
    311 
    312 	if (pa->pa_name && strcmp(pa->pa_name, "fdc") != 0)
    313 		return(0);
    314 
    315 	iot = pa->pa_iot;
    316 	rv = 0;
    317 
    318 	/* Map the i/o space. */
    319 	if (bus_space_map(iot, pa->pa_iobase + pa->pa_offset, FDC_NPORT, 0, &ioh))
    320 		return 0;
    321 
    322 	/* reset */
    323 	bus_space_write_2(iot, ioh, fdout, 0);
    324 	delay(100);
    325 	bus_space_write_2(iot, ioh, fdout, FDO_FRST);
    326 
    327 	/* see if it can handle a command */
    328 	if (out_fdc(iot, ioh, NE7CMD_SPECIFY) < 0)
    329 		goto out;
    330 	out_fdc(iot, ioh, 0xdf);
    331 	out_fdc(iot, ioh, 2);
    332 
    333 	rv = 1;
    334 	pa->pa_iosize = FDC_NPORT;
    335 
    336  out:
    337 	bus_space_unmap(iot, ioh, FDC_NPORT);
    338 	return rv;
    339 }
    340 
    341 /*
    342  * Arguments passed between fdcattach and fdprobe.
    343  */
    344 struct fdc_attach_args {
    345 	int fa_drive;
    346 	struct fd_type *fa_deftype;
    347 };
    348 
    349 /*
    350  * Print the location of a disk drive (called just before attaching the
    351  * the drive).  If `fdc' is not NULL, the drive was found but was not
    352  * in the system config file; print the drive name as well.
    353  * Return QUIET (config_find ignores this if the device was configured) to
    354  * avoid printing `fdN not configured' messages.
    355  */
    356 int
    357 fdprint(aux, fdc)
    358 	void *aux;
    359 	const char *fdc;
    360 {
    361 	register struct fdc_attach_args *fa = aux;
    362 
    363 	if (!fdc)
    364 		aprint_normal(" drive %d", fa->fa_drive);
    365 	return QUIET;
    366 }
    367 
    368 void
    369 fdcattach(parent, self, aux)
    370 	struct device *parent, *self;
    371 	void *aux;
    372 {
    373 	struct fdc_softc *fdc = (void *)self;
    374 	bus_space_tag_t iot;
    375 	bus_space_handle_t ioh;
    376 	struct pioc_attach_args *pa = aux;
    377 	struct fdc_attach_args fa;
    378 	int type;
    379 
    380 	iot = pa->pa_iot;
    381 
    382 	/* Re-map the I/O space. */
    383 	if (bus_space_map(iot, pa->pa_iobase + pa->pa_offset, FDC_NPORT, 0, &ioh))
    384 		panic("fdcattach: couldn't map I/O ports");
    385 
    386 	fdc->sc_iot = iot;
    387 	fdc->sc_ioh = ioh;
    388 
    389 	fdc->sc_drq = pa->pa_iobase + pa->pa_offset + pa->pa_drq;
    390 	fdc->sc_state = DEVIDLE;
    391 	TAILQ_INIT(&fdc->sc_drives);
    392 
    393 	printf("\n");
    394 
    395 	callout_init(&fdc->sc_timo_ch, 0);
    396 	callout_init(&fdc->sc_intr_ch, 0);
    397 
    398 	fdc->sc_ih = intr_claim(pa->pa_irq, IPL_BIO, "fdc",
    399 	    fdcintr, fdc);
    400 	if (!fdc->sc_ih)
    401 		panic("%s: Cannot claim IRQ %d", self->dv_xname, pa->pa_irq);
    402 
    403 #if 0
    404 	/*
    405 	 * The NVRAM info only tells us about the first two disks on the
    406 	 * `primary' floppy controller.
    407 	 */
    408 	if (device_unit(&fdc->sc_dev) == 0)
    409 		type = mc146818_read(NULL, NVRAM_DISKETTE); /* XXX softc */
    410 	else
    411 		type = -1;
    412 #endif
    413 	type = 0x10;	/* XXX - hardcoded for 1 floppy */
    414 
    415 	/* physical limit: four drives per controller. */
    416 	for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
    417 		if (type >= 0 && fa.fa_drive < 2)
    418 			fa.fa_deftype = fd_nvtotype(fdc->sc_dev.dv_xname,
    419 			    type, fa.fa_drive);
    420 		else
    421 			fa.fa_deftype = NULL;		/* unknown */
    422 		(void)config_found(self, (void *)&fa, fdprint);
    423 	}
    424 }
    425 
    426 int
    427 fdprobe(parent, cf, aux)
    428 	struct device *parent;
    429 	struct cfdata *cf;
    430 	void *aux;
    431 {
    432 	struct fdc_softc *fdc = (void *)parent;
    433 	struct fdc_attach_args *fa = aux;
    434 	int drive = fa->fa_drive;
    435 	bus_space_tag_t iot = fdc->sc_iot;
    436 	bus_space_handle_t ioh = fdc->sc_ioh;
    437 	int n;
    438 
    439 	if (cf->cf_loc[FDCCF_DRIVE] != FDCCF_DRIVE_DEFAULT
    440 	  && cf->cf_loc[FDCCF_DRIVE] != drive)
    441 		return 0;
    442 	/*
    443 	 * XXX
    444 	 * This is to work around some odd interactions between this driver
    445 	 * and SMC Ethernet cards.
    446 	 */
    447 
    448 	/* Don't need this for arm32 port but leave for the time being (it won't hurt) */
    449 
    450 	if (cf->cf_loc[FDCCF_DRIVE] == FDCCF_DRIVE_DEFAULT && drive >= 2)
    451 		return 0;
    452 
    453 	/* select drive and turn on motor */
    454 	bus_space_write_2(iot, ioh, fdout, drive | FDO_FRST | FDO_MOEN(drive));
    455 	/* wait for motor to spin up */
    456 	delay(250000);
    457 	out_fdc(iot, ioh, NE7CMD_RECAL);
    458 	out_fdc(iot, ioh, drive);
    459 	/* wait for recalibrate */
    460 	delay(2000000);
    461 	out_fdc(iot, ioh, NE7CMD_SENSEI);
    462 	n = fdcresult(fdc);
    463 #ifdef FD_DEBUG
    464 	{
    465 		int i;
    466 		printf("fdprobe: status");
    467 		for (i = 0; i < n; i++)
    468 			printf(" %x", fdc->sc_status[i]);
    469 		printf("\n");
    470 	}
    471 #endif
    472 	/* turn off motor */
    473 	bus_space_write_1(iot, ioh, fdout, FDO_FRST);
    474 
    475 	if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20)
    476 		return 0;
    477 
    478 	return 1;
    479 }
    480 
    481 /*
    482  * Controller is working, and drive responded.  Attach it.
    483  */
    484 void
    485 fdattach(parent, self, aux)
    486 	struct device *parent, *self;
    487 	void *aux;
    488 {
    489 	struct fdc_softc *fdc = (void *)parent;
    490 	struct fd_softc *fd = (void *)self;
    491 	struct fdc_attach_args *fa = aux;
    492 	struct fd_type *type = fa->fa_deftype;
    493 	int drive = fa->fa_drive;
    494 
    495 	callout_init(&fd->sc_motoron_ch, 0);
    496 	callout_init(&fd->sc_motoroff_ch, 0);
    497 
    498 	/* XXX Allow `flags' to override device type? */
    499 
    500 	if (type)
    501 		printf(": %s %d cyl, %d head, %d sec\n", type->name,
    502 		    type->cyls, type->heads, type->sectrac);
    503 	else
    504 		printf(": density unknown\n");
    505 
    506 	bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER);
    507 	fd->sc_cylin = -1;
    508 	fd->sc_drive = drive;
    509 	fd->sc_deftype = type;
    510 	fdc->sc_fd[drive] = fd;
    511 
    512 	/*
    513 	 * Initialize and attach the disk structure.
    514 	 */
    515 	disk_init(&fd->sc_dk, fd->sc_dev.dv_xname, &fddkdriver);
    516 	disk_attach(&fd->sc_dk);
    517 
    518 	/* Needed to power off if the motor is on when we halt. */
    519 
    520 }
    521 
    522 /*
    523  * Translate nvram type into internal data structure.  Return NULL for
    524  * none/unknown/unusable.
    525  */
    526 struct fd_type *
    527 fd_nvtotype(fdc, nvraminfo, drive)
    528 	char *fdc;
    529 	int nvraminfo, drive;
    530 {
    531 	int type;
    532 
    533 	type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0;
    534 	switch (type) {
    535 #ifndef RC7500
    536 	case 0x00 :
    537 		return NULL;
    538 #else
    539 	case 0x00 :
    540 #endif	/* !RC7500 */
    541 	case 0x10 :
    542 		return &fd_types[0];
    543 	default:
    544 		printf("%s: drive %d: unknown device type 0x%x\n",
    545 		    fdc, drive, type);
    546 		return NULL;
    547 	}
    548 }
    549 
    550 inline struct fd_type *
    551 fd_dev_to_type(fd, dev)
    552 	struct fd_softc *fd;
    553 	dev_t dev;
    554 {
    555 	int type = FDTYPE(dev);
    556 
    557 	if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
    558 		return NULL;
    559 	return type ? &fd_types[type - 1] : fd->sc_deftype;
    560 }
    561 
    562 void
    563 fdstrategy(struct buf *bp)
    564 {
    565 	struct fd_softc *fd = device_lookup_private(&fd_cd,FDUNIT(bp->b_dev));
    566 	int sz;
    567  	int s;
    568 
    569 	/* Valid unit, controller, and request? */
    570 	if (bp->b_blkno < 0 ||
    571 	    ((bp->b_bcount % FDC_BSIZE) != 0 &&
    572 	     (bp->b_flags & B_FORMAT) == 0)) {
    573 		bp->b_error = EINVAL;
    574 		goto done;
    575 	}
    576 
    577 	/* If it's a null transfer, return immediately. */
    578 	if (bp->b_bcount == 0)
    579 		goto done;
    580 
    581 	sz = howmany(bp->b_bcount, FDC_BSIZE);
    582 
    583 	if (bp->b_blkno + sz > fd->sc_type->size) {
    584 		sz = fd->sc_type->size - bp->b_blkno;
    585 		if (sz == 0) {
    586 			/* If exactly at end of disk, return EOF. */
    587 			goto done;
    588 		}
    589 		if (sz < 0) {
    590 			/* If past end of disk, return EINVAL. */
    591 			bp->b_error = EINVAL;
    592 			goto done;
    593 		}
    594 		/* Otherwise, truncate request. */
    595 		bp->b_bcount = sz << DEV_BSHIFT;
    596 	}
    597 
    598 	bp->b_rawblkno = bp->b_blkno;
    599  	bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl;
    600 
    601 #ifdef FD_DEBUG
    602 	printf("fdstrategy: b_blkno %d b_bcount %d blkno %d cylin %d sz %d\n",
    603 	    bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylinder, sz);
    604 #endif
    605 
    606 	/* Queue transfer on drive, activate drive and controller if idle. */
    607 	s = splbio();
    608 	BUFQ_PUT(fd->sc_q, bp);
    609 	callout_stop(&fd->sc_motoroff_ch);		/* a good idea */
    610 	if (fd->sc_active == 0)
    611 		fdstart(fd);
    612 #ifdef DIAGNOSTIC
    613 	else {
    614 		struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
    615 		if (fdc->sc_state == DEVIDLE) {
    616 			printf("fdstrategy: controller inactive\n");
    617 			fdcstart(fdc);
    618 		}
    619 	}
    620 #endif
    621 	splx(s);
    622 	return;
    623 
    624 done:
    625 	/* Toss transfer; we're done early. */
    626 	bp->b_resid = bp->b_bcount;
    627 	biodone(bp);
    628 }
    629 
    630 void
    631 fdstart(fd)
    632 	struct fd_softc *fd;
    633 {
    634 	struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
    635 	int active = fdc->sc_drives.tqh_first != 0;
    636 
    637 	/* Link into controller queue. */
    638 	fd->sc_active = 1;
    639 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    640 
    641 	/* If controller not already active, start it. */
    642 	if (!active)
    643 		fdcstart(fdc);
    644 }
    645 
    646 void
    647 fdfinish(fd, bp)
    648 	struct fd_softc *fd;
    649 	struct buf *bp;
    650 {
    651 	struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
    652 
    653 	/*
    654 	 * Move this drive to the end of the queue to give others a `fair'
    655 	 * chance.  We only force a switch if N operations are completed while
    656 	 * another drive is waiting to be serviced, since there is a long motor
    657 	 * startup delay whenever we switch.
    658 	 */
    659 	(void)BUFQ_GET(fd->sc_q);
    660 	if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
    661 		fd->sc_ops = 0;
    662 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
    663 		if (BUFQ_PEEK(fd->sc_q) != NULL)
    664 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    665 		else
    666 			fd->sc_active = 0;
    667 	}
    668 	bp->b_resid = fd->sc_bcount;
    669 	fd->sc_skip = 0;
    670 
    671 	biodone(bp);
    672 	/* turn off motor 5s from now */
    673 	callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
    674 	fdc->sc_state = DEVIDLE;
    675 }
    676 
    677 int
    678 fdread(dev, uio, flags)
    679 	dev_t dev;
    680 	struct uio *uio;
    681 	int flags;
    682 {
    683 
    684 	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
    685 }
    686 
    687 int
    688 fdwrite(dev, uio, flags)
    689 	dev_t dev;
    690 	struct uio *uio;
    691 	int flags;
    692 {
    693 
    694 	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
    695 }
    696 
    697 void
    698 fd_set_motor(fdc, reset)
    699 	struct fdc_softc *fdc;
    700 	int reset;
    701 {
    702 	struct fd_softc *fd;
    703 	u_char status;
    704 	int n;
    705 
    706 	if ((fd = fdc->sc_drives.tqh_first) != NULL)
    707 		status = fd->sc_drive;
    708 	else
    709 		status = 0;
    710 	if (!reset)
    711 		status |= FDO_FRST | FDO_FDMAEN;
    712 	for (n = 0; n < 4; n++)
    713 		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
    714 			status |= FDO_MOEN(n);
    715 	bus_space_write_2(fdc->sc_iot, fdc->sc_ioh, fdout, status);
    716 }
    717 
    718 void
    719 fd_motor_off(arg)
    720 	void *arg;
    721 {
    722 	struct fd_softc *fd = arg;
    723 	int s;
    724 
    725 	s = splbio();
    726 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
    727 	fd_set_motor((struct fdc_softc *) device_parent(&fd->sc_dev), 0);
    728 	splx(s);
    729 }
    730 
    731 void
    732 fd_motor_on(arg)
    733 	void *arg;
    734 {
    735 	struct fd_softc *fd = arg;
    736 	struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
    737 	int s;
    738 
    739 	s = splbio();
    740 	fd->sc_flags &= ~FD_MOTOR_WAIT;
    741 	if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
    742 		(void) fdcintr(fdc);
    743 	splx(s);
    744 }
    745 
    746 int
    747 fdcresult(fdc)
    748 	struct fdc_softc *fdc;
    749 {
    750 	bus_space_tag_t iot = fdc->sc_iot;
    751 	bus_space_handle_t ioh = fdc->sc_ioh;
    752 	u_char i;
    753 	int j = 100000,
    754 	    n = 0;
    755 
    756 	for (; j; j--) {
    757 		i = bus_space_read_1(iot, ioh, fdsts) &
    758 		    (NE7_DIO | NE7_RQM | NE7_CB);
    759 		if (i == NE7_RQM)
    760 			return n;
    761 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
    762 			if (n >= sizeof(fdc->sc_status)) {
    763 				log(LOG_ERR, "fdcresult: overrun\n");
    764 				return -1;
    765 			}
    766 			fdc->sc_status[n++] =
    767 			    bus_space_read_1(iot, ioh, fddata);
    768 		}
    769 		delay(10);
    770 	}
    771 	log(LOG_ERR, "fdcresult: timeout\n");
    772 	return -1;
    773 }
    774 
    775 int
    776 out_fdc(iot, ioh, x)
    777 	bus_space_tag_t iot;
    778 	bus_space_handle_t ioh;
    779 	u_char x;
    780 {
    781 	int i = 100000;
    782 
    783 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
    784 	if (i <= 0)
    785 		return -1;
    786 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
    787 	if (i <= 0)
    788 		return -1;
    789 	bus_space_write_2(iot, ioh, fddata, x);
    790 	return 0;
    791 }
    792 
    793 int
    794 fdopen(dev_t dev, int flags, int mode, struct lwp *l)
    795 {
    796 	struct fd_softc *fd;
    797 	struct fd_type *type;
    798 
    799 	fd = device_lookup_private(&fd_cd, FDUNIT(dev));
    800 	if (fd == NULL)
    801 		return ENXIO;
    802 	type = fd_dev_to_type(fd, dev);
    803 	if (type == NULL)
    804 		return ENXIO;
    805 
    806 	if ((fd->sc_flags & FD_OPEN) != 0 &&
    807 	    memcmp(fd->sc_type, type, sizeof(*type)))
    808 		return EBUSY;
    809 
    810 	fd->sc_type_copy = *type;
    811 	fd->sc_type = &fd->sc_type_copy;
    812 	fd->sc_cylin = -1;
    813 	fd->sc_flags |= FD_OPEN;
    814 
    815 	return 0;
    816 }
    817 
    818 int
    819 fdclose(dev_t dev, int flags, int mode, struct lwp *l)
    820 {
    821 	struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
    822 
    823 	fd->sc_flags &= ~FD_OPEN;
    824 	fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT);
    825 	return 0;
    826 }
    827 
    828 void
    829 fdcstart(fdc)
    830 	struct fdc_softc *fdc;
    831 {
    832 
    833 #ifdef DIAGNOSTIC
    834 	/* only got here if controller's drive queue was inactive; should
    835 	   be in idle state */
    836 	if (fdc->sc_state != DEVIDLE) {
    837 		printf("fdcstart: not idle\n");
    838 		return;
    839 	}
    840 #endif
    841 	(void) fdcintr(fdc);
    842 }
    843 
    844 static void
    845 fdcpstatus(int n, struct fdc_softc *fdc)
    846 {
    847 	char bits[64];
    848 
    849 	switch (n) {
    850 	case 0:
    851 		printf("\n");
    852 		break;
    853 	case 2:
    854 		snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]);
    855 		printf(" (st0 %s cyl %d)\n", bits, fdc->sc_status[1]);
    856 		break;
    857 	case 7:
    858 		snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]);
    859 		printf(" (st0 %s", bits);
    860 		snprintb(bits, sizeof(bits), NE7_ST1BITS, fdc->sc_status[1]);
    861 		printf(" st1 %s", bits);
    862 		snprintb(bits, sizeof(bits), NE7_ST2BITS, fdc->sc_status[2]);
    863 		printf(" st2 %s", bits);
    864 		printf(" cyl %d head %d sec %d)\n",
    865 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
    866 		break;
    867 #ifdef DIAGNOSTIC
    868 	default:
    869 		printf("\nfdcstatus: weird size");
    870 		break;
    871 #endif
    872 	}
    873 }
    874 
    875 void
    876 fdcstatus(dv, n, s)
    877 	struct device *dv;
    878 	int n;
    879 	const char *s;
    880 {
    881 	struct fdc_softc *fdc = (void *) device_parent(dv);
    882 
    883 	if (n == 0) {
    884 		out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
    885 		(void) fdcresult(fdc);
    886 		n = 2;
    887 	}
    888 
    889 	printf("%s: %s", dv->dv_xname, s);
    890 	fdcpstatus(n, fdc);
    891 }
    892 
    893 void
    894 fdctimeout(arg)
    895 	void *arg;
    896 {
    897 	struct fdc_softc *fdc = arg;
    898 	struct fd_softc *fd = fdc->sc_drives.tqh_first;
    899 	int s;
    900 
    901 	s = splbio();
    902 #ifdef DEBUG
    903 	log(LOG_ERR,"fdctimeout: state %d\n", fdc->sc_state);
    904 #endif
    905 	fdcstatus(&fd->sc_dev, 0, "timeout");
    906 
    907 	if (BUFQ_PEEK(fd->sc_q) != NULL)
    908 		fdc->sc_state++;
    909 	else
    910 		fdc->sc_state = DEVIDLE;
    911 
    912 	(void) fdcintr(fdc);
    913 	splx(s);
    914 }
    915 
    916 void
    917 fdcpseudointr(arg)
    918 	void *arg;
    919 {
    920 	int s;
    921 
    922 	/* Just ensure it has the right spl. */
    923 	s = splbio();
    924 	(void) fdcintr(arg);
    925 	splx(s);
    926 }
    927 
    928 int
    929 fdcintr(arg)
    930 	void *arg;
    931 {
    932 	struct fdc_softc *fdc = arg;
    933 #define	st0	fdc->sc_status[0]
    934 #define	cyl	fdc->sc_status[1]
    935 	struct fd_softc *fd;
    936 	struct buf *bp;
    937 	bus_space_tag_t iot = fdc->sc_iot;
    938 	bus_space_handle_t ioh = fdc->sc_ioh;
    939 	int read, head, sec, i, nblks;
    940 	struct fd_type *type;
    941 	struct ne7_fd_formb *finfo = NULL;
    942 
    943 loop:
    944 	/* Is there a drive for the controller to do a transfer with? */
    945 	fd = fdc->sc_drives.tqh_first;
    946 	if (fd == NULL) {
    947 		fdc->sc_state = DEVIDLE;
    948  		return 1;
    949 	}
    950 
    951 	/* Is there a transfer to this drive?  If not, deactivate drive. */
    952 	bp = BUFQ_PEEK(fd->sc_q);
    953 	if (bp == NULL) {
    954 		fd->sc_ops = 0;
    955 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
    956 		fd->sc_active = 0;
    957 		goto loop;
    958 	}
    959 
    960 	if (bp->b_flags & B_FORMAT)
    961 		finfo = (struct ne7_fd_formb *)bp->b_data;
    962 
    963 	switch (fdc->sc_state) {
    964 	case DEVIDLE:
    965 		fdc->sc_errors = 0;
    966 		fd->sc_skip = 0;
    967 		fd->sc_bcount = bp->b_bcount;
    968 		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
    969 		callout_stop(&fd->sc_motoroff_ch);
    970 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
    971 			fdc->sc_state = MOTORWAIT;
    972 			return 1;
    973 		}
    974 		if ((fd->sc_flags & FD_MOTOR) == 0) {
    975 			/* Turn on the motor, being careful about pairing. */
    976 			struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
    977 			if (ofd && ofd->sc_flags & FD_MOTOR) {
    978 				callout_stop(&ofd->sc_motoroff_ch);
    979 				ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
    980 			}
    981 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
    982 			fd_set_motor(fdc, 0);
    983 			fdc->sc_state = MOTORWAIT;
    984 			/* Allow .25s for motor to stabilize. */
    985 			callout_reset(&fd->sc_motoron_ch, hz / 4,
    986 			    fd_motor_on, fd);
    987 			return 1;
    988 		}
    989 		/* Make sure the right drive is selected. */
    990 		fd_set_motor(fdc, 0);
    991 
    992 		/* fall through */
    993 	case DOSEEK:
    994 	doseek:
    995 		if (fd->sc_cylin == bp->b_cylinder)
    996 			goto doio;
    997 
    998 #if 1
    999 		out_fdc(iot, ioh, NE7CMD_CONFIGURE);/* configure command */
   1000 		out_fdc(iot, ioh, 0);
   1001 		out_fdc(iot, ioh, 0x18);
   1002 		out_fdc(iot, ioh, 0);
   1003 #endif
   1004 		out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
   1005 		out_fdc(iot, ioh, fd->sc_type->steprate);
   1006 		out_fdc(iot, ioh, 6);		/* XXX head load time == 6ms */
   1007 
   1008 		out_fdc(iot, ioh, NE7CMD_SEEK);	/* seek function */
   1009 		out_fdc(iot, ioh, fd->sc_drive);	/* drive number */
   1010 		out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
   1011 
   1012 		fd->sc_cylin = -1;
   1013 		fdc->sc_state = SEEKWAIT;
   1014 
   1015 		iostat_seek(fd->sc_dk.dk_stats);
   1016 		disk_busy(&fd->sc_dk);
   1017 
   1018 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
   1019 		return 1;
   1020 
   1021 	case DOIO:
   1022 	doio:
   1023 		type = fd->sc_type;
   1024 		if (finfo)
   1025 			fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
   1026 				      (char *)finfo;
   1027 		sec = fd->sc_blkno % type->seccyl;
   1028 		nblks = type->seccyl - sec;
   1029 		nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
   1030 		nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
   1031 		fd->sc_nblks = nblks;
   1032 		fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
   1033 		head = sec / type->sectrac;
   1034 		sec -= head * type->sectrac;
   1035 #ifdef DIAGNOSTIC
   1036 		{daddr_t  block;
   1037 		 block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec;
   1038 		 if (block != fd->sc_blkno) {
   1039 			 printf("fdcintr: block %" PRId64
   1040 			     " != blkno %" PRId64 "\n",
   1041 				block, fd->sc_blkno);
   1042 #ifdef DDB
   1043 			 Debugger();
   1044 #endif
   1045 		 }}
   1046 #endif
   1047 		read = bp->b_flags & B_READ;
   1048 		if (read) {
   1049 			fdc->sc_fh.fh_func = floppy_read_fiq;
   1050 			fdc->sc_fh.fh_size = floppy_read_fiq_end -
   1051 			    floppy_read_fiq;
   1052 		} else {
   1053 			fdc->sc_fh.fh_func = floppy_write_fiq;
   1054 			fdc->sc_fh.fh_size = floppy_read_fiq_end -
   1055 			    floppy_read_fiq;
   1056 		}
   1057 		fdc->sc_fh.fh_flags = 0;
   1058 		fdc->sc_fh.fh_regs = &fdc->sc_fr;
   1059 		fdc->sc_fr.fr_r9 = IOMD_BASE + (IOMD_FIQRQ << 2);
   1060 		fdc->sc_fr.fr_r10 = fd->sc_nbytes;
   1061 		fdc->sc_fr.fr_r11 =
   1062 		    (u_int)((uintptr_t)bp->b_data + fd->sc_skip);
   1063 		fdc->sc_fr.fr_r12 = fdc->sc_drq;
   1064 #ifdef FD_DEBUG
   1065 		printf("fdc-doio:r9=%x r10=%x r11=%x r12=%x data=%x skip=%x\n",
   1066 		    fdc->sc_fr.fr_r9, fdc->sc_fr.fh_r10, fdc->sc_fr.fh_r11,
   1067 		    fdc->sc_fr.fh_r12, (u_int)bp->b_data, fd->sc_skip);
   1068 #endif
   1069 		if (fiq_claim(&fdc->sc_fh) == -1)
   1070 			panic("%s: Cannot claim FIQ vector", fdc->sc_dev.dv_xname);
   1071 		IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x01);
   1072 		bus_space_write_2(iot, ioh, fdctl, type->rate);
   1073 #ifdef FD_DEBUG
   1074 		printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
   1075 			read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
   1076 			head, sec, nblks);
   1077 #endif
   1078 		if (finfo) {
   1079 			/* formatting */
   1080 			if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) {
   1081 				fdc->sc_errors = 4;
   1082 				fdcretry(fdc);
   1083 				goto loop;
   1084 			}
   1085 			out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1086 			out_fdc(iot, ioh, finfo->fd_formb_secshift);
   1087 			out_fdc(iot, ioh, finfo->fd_formb_nsecs);
   1088 			out_fdc(iot, ioh, finfo->fd_formb_gaplen);
   1089 			out_fdc(iot, ioh, finfo->fd_formb_fillbyte);
   1090 		} else {
   1091 			if (read)
   1092 				out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
   1093 			else
   1094 				out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
   1095 			out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1096 			out_fdc(iot, ioh, fd->sc_cylin); /* track */
   1097 			out_fdc(iot, ioh, head);
   1098 			out_fdc(iot, ioh, sec + 1);	 /* sector +1 */
   1099 			out_fdc(iot, ioh, type->secsize);/* sector size */
   1100 			out_fdc(iot, ioh, type->sectrac);/* sectors/track */
   1101 			out_fdc(iot, ioh, type->gap1);	 /* gap1 size */
   1102 			out_fdc(iot, ioh, type->datalen);/* data length */
   1103 		}
   1104 		fdc->sc_state = IOCOMPLETE;
   1105 
   1106 		disk_busy(&fd->sc_dk);
   1107 
   1108 		/* allow 2 seconds for operation */
   1109 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1110 		return 1;				/* will return later */
   1111 
   1112 	case SEEKWAIT:
   1113 		callout_stop(&fdc->sc_timo_ch);
   1114 		fdc->sc_state = SEEKCOMPLETE;
   1115 		/* allow 1/50 second for heads to settle */
   1116 #if 0
   1117 		callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
   1118 #endif
   1119 		return 1;
   1120 
   1121 	case SEEKCOMPLETE:
   1122 		/* no data on seek */
   1123 		disk_unbusy(&fd->sc_dk, 0, 0);
   1124 
   1125 		/* Make sure seek really happened. */
   1126 		out_fdc(iot, ioh, NE7CMD_SENSEI);
   1127 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
   1128 		    cyl != bp->b_cylinder * fd->sc_type->step) {
   1129 #ifdef FD_DEBUG
   1130 			fdcstatus(&fd->sc_dev, 2, "seek failed");
   1131 #endif
   1132 			fdcretry(fdc);
   1133 			goto loop;
   1134 		}
   1135 		fd->sc_cylin = bp->b_cylinder;
   1136 		goto doio;
   1137 
   1138 	case IOTIMEDOUT:
   1139 		fiq_release(&fdc->sc_fh);
   1140 		IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
   1141 	case SEEKTIMEDOUT:
   1142 	case RECALTIMEDOUT:
   1143 	case RESETTIMEDOUT:
   1144 		fdcretry(fdc);
   1145 		goto loop;
   1146 
   1147 	case IOCOMPLETE: /* IO DONE, post-analyze */
   1148 		callout_stop(&fdc->sc_timo_ch);
   1149 
   1150 		disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
   1151 		    (bp->b_flags & B_READ));
   1152 
   1153 		if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) {
   1154 			fiq_release(&fdc->sc_fh);
   1155 			IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
   1156 #ifdef FD_DEBUG
   1157 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
   1158 			    "read failed" : "write failed");
   1159 			printf("blkno %d nblks %d\n",
   1160 			    fd->sc_blkno, fd->sc_nblks);
   1161 #endif
   1162 			fdcretry(fdc);
   1163 			goto loop;
   1164 		}
   1165 		fiq_release(&fdc->sc_fh);
   1166 		IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
   1167 		if (fdc->sc_errors) {
   1168 #if 0
   1169 			diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
   1170 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
   1171 			printf("\n");
   1172 #endif
   1173 			fdc->sc_errors = 0;
   1174 		}
   1175 		fd->sc_blkno += fd->sc_nblks;
   1176 		fd->sc_skip += fd->sc_nbytes;
   1177 		fd->sc_bcount -= fd->sc_nbytes;
   1178 		if (!finfo && fd->sc_bcount > 0) {
   1179 			bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
   1180 			goto doseek;
   1181 		}
   1182 		fdfinish(fd, bp);
   1183 		goto loop;
   1184 
   1185 	case DORESET:
   1186 		/* try a reset, keep motor on */
   1187 		fd_set_motor(fdc, 1);
   1188 		delay(100);
   1189 		fd_set_motor(fdc, 0);
   1190 		fdc->sc_state = RESETCOMPLETE;
   1191 		callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
   1192 		return 1;			/* will return later */
   1193 
   1194 	case RESETCOMPLETE:
   1195 		callout_stop(&fdc->sc_timo_ch);
   1196 		/* clear the controller output buffer */
   1197 		for (i = 0; i < 4; i++) {
   1198 			out_fdc(iot, ioh, NE7CMD_SENSEI);
   1199 			(void) fdcresult(fdc);
   1200 		}
   1201 
   1202 		/* fall through */
   1203 	case DORECAL:
   1204 		out_fdc(iot, ioh, NE7CMD_RECAL);	/* recalibrate function */
   1205 		out_fdc(iot, ioh, fd->sc_drive);
   1206 		fdc->sc_state = RECALWAIT;
   1207 		callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
   1208 		return 1;			/* will return later */
   1209 
   1210 	case RECALWAIT:
   1211 		callout_stop(&fdc->sc_timo_ch);
   1212 		fdc->sc_state = RECALCOMPLETE;
   1213 		/* allow 1/30 second for heads to settle */
   1214 #if 0
   1215 		callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
   1216 #endif
   1217 		return 1;			/* will return later */
   1218 
   1219 	case RECALCOMPLETE:
   1220 		out_fdc(iot, ioh, NE7CMD_SENSEI);
   1221 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
   1222 #ifdef FD_DEBUG
   1223 			fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
   1224 #endif
   1225 			fdcretry(fdc);
   1226 			goto loop;
   1227 		}
   1228 		fd->sc_cylin = 0;
   1229 		goto doseek;
   1230 
   1231 	case MOTORWAIT:
   1232 		if (fd->sc_flags & FD_MOTOR_WAIT)
   1233 			return 1;		/* time's not up yet */
   1234 		goto doseek;
   1235 
   1236 	default:
   1237 		fdcstatus(&fd->sc_dev, 0, "stray interrupt");
   1238 		return 1;
   1239 	}
   1240 #ifdef DIAGNOSTIC
   1241 	panic("fdcintr: impossible");
   1242 #endif
   1243 #undef	st0
   1244 #undef	cyl
   1245 }
   1246 
   1247 void
   1248 fdcretry(fdc)
   1249 	struct fdc_softc *fdc;
   1250 {
   1251 	struct fd_softc *fd;
   1252 	struct buf *bp;
   1253 
   1254 	fd = fdc->sc_drives.tqh_first;
   1255 	bp = BUFQ_PEEK(fd->sc_q);
   1256 
   1257 	if (fd->sc_opts & FDOPT_NORETRY)
   1258 	    goto fail;
   1259 	switch (fdc->sc_errors) {
   1260 	case 0:
   1261 		/* try again */
   1262 		fdc->sc_state = DOSEEK;
   1263 		break;
   1264 
   1265 	case 1: case 2: case 3:
   1266 		/* didn't work; try recalibrating */
   1267 		fdc->sc_state = DORECAL;
   1268 		break;
   1269 
   1270 	case 4:
   1271 		/* still no go; reset the bastard */
   1272 		fdc->sc_state = DORESET;
   1273 		break;
   1274 
   1275 	default:
   1276 	fail:
   1277 		if ((fd->sc_opts & FDOPT_SILENT) == 0) {
   1278 			diskerr(bp, "fd", "hard error", LOG_PRINTF,
   1279 				fd->sc_skip / FDC_BSIZE,
   1280 				(struct disklabel *)NULL);
   1281 			fdcpstatus(7, fdc);
   1282 		}
   1283 
   1284 		bp->b_error = EIO;
   1285 		fdfinish(fd, bp);
   1286 	}
   1287 	fdc->sc_errors++;
   1288 }
   1289 
   1290 int
   1291 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
   1292 {
   1293 	struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
   1294 	struct fdformat_parms *form_parms;
   1295 	struct fdformat_cmd *form_cmd;
   1296 	struct ne7_fd_formb *fd_formb;
   1297 	struct disklabel buffer;
   1298 	int error;
   1299 	unsigned int scratch;
   1300 	int il[FD_MAX_NSEC + 1];
   1301 	register int i, j;
   1302 
   1303 	switch (cmd) {
   1304 	case DIOCGDINFO:
   1305 		memset(&buffer, 0, sizeof(buffer));
   1306 
   1307 		buffer.d_secpercyl = fd->sc_type->seccyl;
   1308 		buffer.d_type = DTYPE_FLOPPY;
   1309 		buffer.d_secsize = FDC_BSIZE;
   1310 
   1311 		if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
   1312 			return EINVAL;
   1313 
   1314 		*(struct disklabel *)addr = buffer;
   1315 		return 0;
   1316 
   1317 	case DIOCWLABEL:
   1318 		if ((flag & FWRITE) == 0)
   1319 			return EBADF;
   1320 		/* XXX do something */
   1321 		return 0;
   1322 
   1323 	case DIOCWDINFO:
   1324 		if ((flag & FWRITE) == 0)
   1325 			return EBADF;
   1326 
   1327 		error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
   1328 		if (error)
   1329 			return error;
   1330 
   1331 		error = writedisklabel(dev, fdstrategy, &buffer, NULL);
   1332 		return error;
   1333 
   1334 	case FDIOCGETFORMAT:
   1335 		form_parms = (struct fdformat_parms *)addr;
   1336 		form_parms->fdformat_version = FDFORMAT_VERSION;
   1337 		form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
   1338 		form_parms->ncyl = fd->sc_type->cyls;
   1339 		form_parms->nspt = fd->sc_type->sectrac;
   1340 		form_parms->ntrk = fd->sc_type->heads;
   1341 		form_parms->stepspercyl = fd->sc_type->step;
   1342 		form_parms->gaplen = fd->sc_type->gap2;
   1343 		form_parms->fillbyte = fd->sc_type->fillbyte;
   1344 		form_parms->interleave = fd->sc_type->interleave;
   1345 		switch (fd->sc_type->rate) {
   1346 		case FDC_500KBPS:
   1347 			form_parms->xfer_rate = 500 * 1024;
   1348 			break;
   1349 		case FDC_300KBPS:
   1350 			form_parms->xfer_rate = 300 * 1024;
   1351 			break;
   1352 		case FDC_250KBPS:
   1353 			form_parms->xfer_rate = 250 * 1024;
   1354 			break;
   1355 		default:
   1356 			return EINVAL;
   1357 		}
   1358 		return 0;
   1359 
   1360 	case FDIOCSETFORMAT:
   1361 		if((flag & FWRITE) == 0)
   1362 			return EBADF;	/* must be opened for writing */
   1363 		form_parms = (struct fdformat_parms *)addr;
   1364 		if (form_parms->fdformat_version != FDFORMAT_VERSION)
   1365 			return EINVAL;	/* wrong version of formatting prog */
   1366 
   1367 		scratch = form_parms->nbps >> 7;
   1368 		if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
   1369 		    scratch & ~(1 << (ffs(scratch)-1)))
   1370 			/* not a power-of-two multiple of 128 */
   1371 			return EINVAL;
   1372 
   1373 		switch (form_parms->xfer_rate) {
   1374 		case 500 * 1024:
   1375 			fd->sc_type->rate = FDC_500KBPS;
   1376 			break;
   1377 		case 300 * 1024:
   1378 			fd->sc_type->rate = FDC_300KBPS;
   1379 			break;
   1380 		case 250 * 1024:
   1381 			fd->sc_type->rate = FDC_250KBPS;
   1382 			break;
   1383 		default:
   1384 			return EINVAL;
   1385 		}
   1386 
   1387 		if (form_parms->nspt > FD_MAX_NSEC ||
   1388 		    form_parms->fillbyte > 0xff ||
   1389 		    form_parms->interleave > 0xff)
   1390 			return EINVAL;
   1391 		fd->sc_type->sectrac = form_parms->nspt;
   1392 		if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
   1393 			return EINVAL;
   1394 		fd->sc_type->heads = form_parms->ntrk;
   1395 		fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
   1396 		fd->sc_type->secsize = ffs(scratch)-1;
   1397 		fd->sc_type->gap2 = form_parms->gaplen;
   1398 		fd->sc_type->cyls = form_parms->ncyl;
   1399 		fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
   1400 			form_parms->nbps / DEV_BSIZE;
   1401 		fd->sc_type->step = form_parms->stepspercyl;
   1402 		fd->sc_type->fillbyte = form_parms->fillbyte;
   1403 		fd->sc_type->interleave = form_parms->interleave;
   1404 		return 0;
   1405 
   1406 	case FDIOCFORMAT_TRACK:
   1407 		if((flag & FWRITE) == 0)
   1408 			return EBADF;	/* must be opened for writing */
   1409 		form_cmd = (struct fdformat_cmd *)addr;
   1410 		if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
   1411 			return EINVAL;	/* wrong version of formatting prog */
   1412 
   1413 		if (form_cmd->head >= fd->sc_type->heads ||
   1414 		    form_cmd->cylinder >= fd->sc_type->cyls) {
   1415 			return EINVAL;
   1416 		}
   1417 
   1418 		fd_formb = malloc(sizeof(struct ne7_fd_formb),
   1419 		    M_TEMP, M_NOWAIT);
   1420 		if(fd_formb == 0)
   1421 			return ENOMEM;
   1422 
   1423 
   1424 		fd_formb->head = form_cmd->head;
   1425 		fd_formb->cyl = form_cmd->cylinder;
   1426 		fd_formb->transfer_rate = fd->sc_type->rate;
   1427 		fd_formb->fd_formb_secshift = fd->sc_type->secsize;
   1428 		fd_formb->fd_formb_nsecs = fd->sc_type->sectrac;
   1429 		fd_formb->fd_formb_gaplen = fd->sc_type->gap2;
   1430 		fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte;
   1431 
   1432 		memset(il, 0, sizeof il);
   1433 		for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) {
   1434 			while (il[(j%fd_formb->fd_formb_nsecs)+1])
   1435 				j++;
   1436 			il[(j%fd_formb->fd_formb_nsecs)+1] = i;
   1437 			j += fd->sc_type->interleave;
   1438 		}
   1439 		for (i = 0; i < fd_formb->fd_formb_nsecs; i++) {
   1440 			fd_formb->fd_formb_cylno(i) = form_cmd->cylinder;
   1441 			fd_formb->fd_formb_headno(i) = form_cmd->head;
   1442 			fd_formb->fd_formb_secno(i) = il[i+1];
   1443 			fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize;
   1444 		}
   1445 
   1446 		error = fdformat(dev, fd_formb, l);
   1447 		free(fd_formb, M_TEMP);
   1448 		return error;
   1449 
   1450 	case FDIOCGETOPTS:		/* get drive options */
   1451 		*(int *)addr = fd->sc_opts;
   1452 		return 0;
   1453 
   1454 	case FDIOCSETOPTS:		/* set drive options */
   1455 		fd->sc_opts = *(int *)addr;
   1456 		return 0;
   1457 
   1458 	default:
   1459 		return ENOTTY;
   1460 	}
   1461 
   1462 #ifdef DIAGNOSTIC
   1463 	panic("fdioctl: impossible");
   1464 #endif
   1465 }
   1466 
   1467 int
   1468 fdformat(dev_t dev, struct ne7_fd_formb *finfo, struct lwp *l)
   1469 {
   1470 	int rv = 0;
   1471 	struct fd_softc *fd = device_lookup_private(&fd_cd,FDUNIT(dev));
   1472 	struct fd_type *type = fd->sc_type;
   1473 	struct buf *bp;
   1474 
   1475 	/* set up a buffer header for fdstrategy() */
   1476 	bp = getiobuf(NULL, false);
   1477 	if(bp == 0)
   1478 		return ENOBUFS;
   1479 	bp->b_flags = B_PHYS | B_FORMAT;
   1480 	bp->b_cflags |= BC_BUSY;
   1481 	bp->b_proc = l->l_proc;
   1482 	bp->b_dev = dev;
   1483 
   1484 	/*
   1485 	 * calculate a fake blkno, so fdstrategy() would initiate a
   1486 	 * seek to the requested cylinder
   1487 	 */
   1488 	bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
   1489 		       + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
   1490 
   1491 	bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
   1492 	bp->b_data = (void *)finfo;
   1493 
   1494 #ifdef DEBUG
   1495 	printf("fdformat: blkno %llx count %lx\n",
   1496 	    (unsigned long long)bp->b_blkno, bp->b_bcount);
   1497 #endif
   1498 
   1499 	/* now do the format */
   1500 	fdstrategy(bp);
   1501 
   1502 	/* ...and wait for it to complete */
   1503 	/* XXX very dodgy */
   1504 	mutex_enter(bp->b_objlock);
   1505 	while (!(bp->b_oflags & BO_DONE)) {
   1506 		rv = cv_timedwait(&bp->b_done, bp->b_objlock, 20 * hz);
   1507 		if (rv == EWOULDBLOCK)
   1508 			break;
   1509 	}
   1510 	mutex_exit(bp->b_objlock);
   1511 
   1512 	if (rv == EWOULDBLOCK) {
   1513 		/* timed out */
   1514 		rv = EIO;
   1515 		biodone(bp);
   1516 	} else if (bp->b_error != 0)
   1517 		rv = bp->b_error;
   1518 	putiobuf(bp);
   1519 	return rv;
   1520 }
   1521 
   1522 #include "md.h"
   1523 #if NMD > 0
   1524 
   1525 #include <dev/md.h>
   1526 
   1527 int load_memory_disc_from_floppy __P((struct md_conf *md, dev_t dev));
   1528 
   1529 int
   1530 load_memory_disc_from_floppy(md, dev)
   1531 	struct md_conf *md;
   1532 	dev_t dev;
   1533 {
   1534 	struct buf *bp;
   1535 	int loop;
   1536 	int s;
   1537 	int type;
   1538 	int floppysize;
   1539 
   1540 	if (bdevsw_lookup(dev) != &fd_bdevsw)
   1541 		return(EINVAL);
   1542 
   1543 	if (md->md_type == MD_UNCONFIGURED || md->md_addr == 0)
   1544 		return(EBUSY);
   1545 
   1546 	type = FDTYPE(dev) - 1;
   1547 	if (type < 0) type = 0;
   1548 	floppysize = fd_types[type].size << (fd_types[type].secsize + 7);
   1549 
   1550 	if (md->md_size < floppysize) {
   1551 		printf("Memory disc is not big enough for floppy image\n");
   1552 		return(EINVAL);
   1553 	}
   1554 
   1555 /* We have the memory disk ! */
   1556 
   1557 	printf("Loading memory disc : %4dK ", 0);
   1558 
   1559 /* obtain a buffer */
   1560 
   1561 	bp = geteblk(fd_types[type].sectrac * DEV_BSIZE);
   1562 
   1563 /* request no partition relocation by driver on I/O operations */
   1564 
   1565 	bp->b_dev = dev;
   1566 
   1567 	s = spl0();
   1568 
   1569 	if (fdopen(bp->b_dev, 0, 0, curlwp) != 0) {
   1570 		brelse(bp, 0);
   1571 		printf("Cannot open floppy device\n");
   1572 			return(EINVAL);
   1573 	}
   1574 
   1575 	for (loop = 0;
   1576 	    loop < (floppysize / DEV_BSIZE / fd_types[type].sectrac);
   1577 	    ++loop) {
   1578 		printf("\x08\x08\x08\x08\x08\x08%4dK ",
   1579 		    loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
   1580 		bp->b_blkno = loop * fd_types[type].sectrac;
   1581 		bp->b_bcount = fd_types[type].sectrac * DEV_BSIZE;
   1582 		bp->b_flags |= B_READ;
   1583 		bp->b_error = 0;
   1584 		bp->b_resid = 0;
   1585 		fdstrategy(bp);
   1586 
   1587 		if (biowait(bp))
   1588 			panic("Cannot load floppy image");
   1589 
   1590 		memcpy((char *)md->md_addr + loop * fd_types[type].sectrac
   1591 		    * DEV_BSIZE, (void *)bp->b_data,
   1592 		    fd_types[type].sectrac * DEV_BSIZE);
   1593 	}
   1594 	printf("\x08\x08\x08\x08\x08\x08%4dK done\n",
   1595 	    loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
   1596 
   1597 	fdclose(bp->b_dev, 0, 0, curlwp);
   1598 
   1599 	brelse(bp, 0);
   1600 
   1601 	splx(s);
   1602 	return(0);
   1603 }
   1604 
   1605 #endif
   1606