Home | History | Annotate | Line # | Download | only in mainbus
fd.c revision 1.39
      1 /*	$NetBSD: fd.c,v 1.39 2008/06/12 23:22:36 cegger Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Charles M. Hannum.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*-
     33  * Copyright (c) 1990 The Regents of the University of California.
     34  * All rights reserved.
     35  *
     36  * This code is derived from software contributed to Berkeley by
     37  * Don Ahn.
     38  *
     39  * Redistribution and use in source and binary forms, with or without
     40  * modification, are permitted provided that the following conditions
     41  * are met:
     42  * 1. Redistributions of source code must retain the above copyright
     43  *    notice, this list of conditions and the following disclaimer.
     44  * 2. Redistributions in binary form must reproduce the above copyright
     45  *    notice, this list of conditions and the following disclaimer in the
     46  *    documentation and/or other materials provided with the distribution.
     47  * 3. Neither the name of the University nor the names of its contributors
     48  *    may be used to endorse or promote products derived from this software
     49  *    without specific prior written permission.
     50  *
     51  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     52  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     53  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     54  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     55  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     56  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     57  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     58  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     59  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     60  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     61  * SUCH DAMAGE.
     62  *
     63  *	@(#)fd.c	7.4 (Berkeley) 5/25/91
     64  *	from: fd.c,v 1.104 1997/01/09 04:30:08 mycroft Exp
     65  */
     66 
     67 /*
     68  * Floppy formatting facilities merged from FreeBSD fd.c driver:
     69  *	Id: fd.c,v 1.53 1995/03/12 22:40:56 joerg Exp
     70  * which carries the same copyright/redistribution notice as shown above with
     71  * the addition of the following statement before the "Redistribution and
     72  * use ..." clause:
     73  *
     74  * Copyright (c) 1993, 1994 by
     75  *  jc (at) irbs.UUCP (John Capo)
     76  *  vak (at) zebub.msk.su (Serge Vakulenko)
     77  *  ache (at) astral.msk.su (Andrew A. Chernov)
     78  *
     79  * Copyright (c) 1993, 1994, 1995 by
     80  *  joerg_wunsch (at) uriah.sax.de (Joerg Wunsch)
     81  *  dufault (at) hda.com (Peter Dufault)
     82  */
     83 
     84 #include <sys/cdefs.h>
     85 __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.39 2008/06/12 23:22:36 cegger Exp $");
     86 
     87 #include "opt_ddb.h"
     88 
     89 #include <sys/param.h>
     90 #include <sys/systm.h>
     91 #include <sys/callout.h>
     92 #include <sys/kernel.h>
     93 #include <sys/file.h>
     94 #include <sys/ioctl.h>
     95 #include <sys/device.h>
     96 #include <sys/disklabel.h>
     97 #include <sys/disk.h>
     98 #include <sys/buf.h>
     99 #include <sys/bufq.h>
    100 #include <sys/malloc.h>
    101 #include <sys/uio.h>
    102 #include <sys/syslog.h>
    103 #include <sys/queue.h>
    104 #include <sys/proc.h>
    105 #include <sys/fdio.h>
    106 #include <sys/conf.h>
    107 
    108 #include <uvm/uvm_extern.h>
    109 
    110 #include <arm/fiq.h>
    111 
    112 #include <machine/cpu.h>
    113 #include <machine/intr.h>
    114 #include <machine/io.h>
    115 #include <arm/arm32/katelib.h>
    116 #include <machine/bus.h>
    117 
    118 #include <arm/iomd/iomdreg.h>
    119 #include <arm/iomd/iomdvar.h>
    120 
    121 #include <acorn32/mainbus/piocvar.h>
    122 #include <acorn32/mainbus/fdreg.h>
    123 
    124 #include "locators.h"
    125 
    126 #define NE7CMD_CONFIGURE 0x13
    127 
    128 #define FDUNIT(dev)	(minor(dev) / 8)
    129 #define FDTYPE(dev)	(minor(dev) % 8)
    130 
    131 /* (mis)use device use flag to identify format operation */
    132 #define B_FORMAT B_DEVPRIVATE
    133 
    134 enum fdc_state {
    135 	DEVIDLE = 0,
    136 	MOTORWAIT,
    137 	DOSEEK,
    138 	SEEKWAIT,
    139 	SEEKTIMEDOUT,
    140 	SEEKCOMPLETE,
    141 	DOIO,
    142 	IOCOMPLETE,
    143 	IOTIMEDOUT,
    144 	DORESET,
    145 	RESETCOMPLETE,
    146 	RESETTIMEDOUT,
    147 	DORECAL,
    148 	RECALWAIT,
    149 	RECALTIMEDOUT,
    150 	RECALCOMPLETE,
    151 };
    152 
    153 /* software state, per controller */
    154 struct fdc_softc {
    155 	struct device sc_dev;		/* boilerplate */
    156 	void *sc_ih;
    157 
    158 	bus_space_tag_t sc_iot;		/* ISA i/o space identifier */
    159 	bus_space_handle_t   sc_ioh;	/* ISA io handle */
    160 
    161 	struct callout sc_timo_ch;	/* timeout callout */
    162 	struct callout sc_intr_ch;	/* pseudo-intr callout */
    163 
    164 	/* ...for pseudo-DMA... */
    165 	struct fiqhandler sc_fh;	/* FIQ handler descriptor */
    166 	struct fiqregs sc_fr;		/* FIQ handler reg context */
    167 	int sc_drq;
    168 
    169 	struct fd_softc *sc_fd[4];	/* pointers to children */
    170 	TAILQ_HEAD(drivehead, fd_softc) sc_drives;
    171 	enum fdc_state sc_state;
    172 	int sc_errors;			/* number of retries so far */
    173 	u_char sc_status[7];		/* copy of registers */
    174 };
    175 
    176 /* controller driver configuration */
    177 int fdcprobe __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 void
    845 fdcstatus(dv, n, s)
    846 	struct device *dv;
    847 	int n;
    848 	const char *s;
    849 {
    850 	struct fdc_softc *fdc = (void *) device_parent(dv);
    851 	char bits[64];
    852 
    853 	if (n == 0) {
    854 		out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
    855 		(void) fdcresult(fdc);
    856 		n = 2;
    857 	}
    858 
    859 	printf("%s: %s", dv->dv_xname, s);
    860 
    861 	switch (n) {
    862 	case 0:
    863 		printf("\n");
    864 		break;
    865 	case 2:
    866 		printf(" (st0 %s cyl %d)\n",
    867 		    bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
    868 		    bits, sizeof(bits)), fdc->sc_status[1]);
    869 		break;
    870 	case 7:
    871 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
    872 		    NE7_ST0BITS, bits, sizeof(bits)));
    873 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
    874 		    NE7_ST1BITS, bits, sizeof(bits)));
    875 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
    876 		    NE7_ST2BITS, bits, sizeof(bits)));
    877 		printf(" cyl %d head %d sec %d)\n",
    878 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
    879 		break;
    880 #ifdef DIAGNOSTIC
    881 	default:
    882 		printf("\nfdcstatus: weird size");
    883 		break;
    884 #endif
    885 	}
    886 }
    887 
    888 void
    889 fdctimeout(arg)
    890 	void *arg;
    891 {
    892 	struct fdc_softc *fdc = arg;
    893 	struct fd_softc *fd = fdc->sc_drives.tqh_first;
    894 	int s;
    895 
    896 	s = splbio();
    897 #ifdef DEBUG
    898 	log(LOG_ERR,"fdctimeout: state %d\n", fdc->sc_state);
    899 #endif
    900 	fdcstatus(&fd->sc_dev, 0, "timeout");
    901 
    902 	if (BUFQ_PEEK(fd->sc_q) != NULL)
    903 		fdc->sc_state++;
    904 	else
    905 		fdc->sc_state = DEVIDLE;
    906 
    907 	(void) fdcintr(fdc);
    908 	splx(s);
    909 }
    910 
    911 void
    912 fdcpseudointr(arg)
    913 	void *arg;
    914 {
    915 	int s;
    916 
    917 	/* Just ensure it has the right spl. */
    918 	s = splbio();
    919 	(void) fdcintr(arg);
    920 	splx(s);
    921 }
    922 
    923 int
    924 fdcintr(arg)
    925 	void *arg;
    926 {
    927 	struct fdc_softc *fdc = arg;
    928 #define	st0	fdc->sc_status[0]
    929 #define	cyl	fdc->sc_status[1]
    930 	struct fd_softc *fd;
    931 	struct buf *bp;
    932 	bus_space_tag_t iot = fdc->sc_iot;
    933 	bus_space_handle_t ioh = fdc->sc_ioh;
    934 	int read, head, sec, i, nblks;
    935 	struct fd_type *type;
    936 	struct ne7_fd_formb *finfo = NULL;
    937 
    938 loop:
    939 	/* Is there a drive for the controller to do a transfer with? */
    940 	fd = fdc->sc_drives.tqh_first;
    941 	if (fd == NULL) {
    942 		fdc->sc_state = DEVIDLE;
    943  		return 1;
    944 	}
    945 
    946 	/* Is there a transfer to this drive?  If not, deactivate drive. */
    947 	bp = BUFQ_PEEK(fd->sc_q);
    948 	if (bp == NULL) {
    949 		fd->sc_ops = 0;
    950 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
    951 		fd->sc_active = 0;
    952 		goto loop;
    953 	}
    954 
    955 	if (bp->b_flags & B_FORMAT)
    956 		finfo = (struct ne7_fd_formb *)bp->b_data;
    957 
    958 	switch (fdc->sc_state) {
    959 	case DEVIDLE:
    960 		fdc->sc_errors = 0;
    961 		fd->sc_skip = 0;
    962 		fd->sc_bcount = bp->b_bcount;
    963 		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
    964 		callout_stop(&fd->sc_motoroff_ch);
    965 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
    966 			fdc->sc_state = MOTORWAIT;
    967 			return 1;
    968 		}
    969 		if ((fd->sc_flags & FD_MOTOR) == 0) {
    970 			/* Turn on the motor, being careful about pairing. */
    971 			struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
    972 			if (ofd && ofd->sc_flags & FD_MOTOR) {
    973 				callout_stop(&ofd->sc_motoroff_ch);
    974 				ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
    975 			}
    976 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
    977 			fd_set_motor(fdc, 0);
    978 			fdc->sc_state = MOTORWAIT;
    979 			/* Allow .25s for motor to stabilize. */
    980 			callout_reset(&fd->sc_motoron_ch, hz / 4,
    981 			    fd_motor_on, fd);
    982 			return 1;
    983 		}
    984 		/* Make sure the right drive is selected. */
    985 		fd_set_motor(fdc, 0);
    986 
    987 		/* fall through */
    988 	case DOSEEK:
    989 	doseek:
    990 		if (fd->sc_cylin == bp->b_cylinder)
    991 			goto doio;
    992 
    993 #if 1
    994 		out_fdc(iot, ioh, NE7CMD_CONFIGURE);/* configure command */
    995 		out_fdc(iot, ioh, 0);
    996 		out_fdc(iot, ioh, 0x18);
    997 		out_fdc(iot, ioh, 0);
    998 #endif
    999 		out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
   1000 		out_fdc(iot, ioh, fd->sc_type->steprate);
   1001 		out_fdc(iot, ioh, 6);		/* XXX head load time == 6ms */
   1002 
   1003 		out_fdc(iot, ioh, NE7CMD_SEEK);	/* seek function */
   1004 		out_fdc(iot, ioh, fd->sc_drive);	/* drive number */
   1005 		out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
   1006 
   1007 		fd->sc_cylin = -1;
   1008 		fdc->sc_state = SEEKWAIT;
   1009 
   1010 		iostat_seek(fd->sc_dk.dk_stats);
   1011 		disk_busy(&fd->sc_dk);
   1012 
   1013 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
   1014 		return 1;
   1015 
   1016 	case DOIO:
   1017 	doio:
   1018 		type = fd->sc_type;
   1019 		if (finfo)
   1020 			fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
   1021 				      (char *)finfo;
   1022 		sec = fd->sc_blkno % type->seccyl;
   1023 		nblks = type->seccyl - sec;
   1024 		nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
   1025 		nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
   1026 		fd->sc_nblks = nblks;
   1027 		fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
   1028 		head = sec / type->sectrac;
   1029 		sec -= head * type->sectrac;
   1030 #ifdef DIAGNOSTIC
   1031 		{daddr_t  block;
   1032 		 block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec;
   1033 		 if (block != fd->sc_blkno) {
   1034 			 printf("fdcintr: block %" PRId64
   1035 			     " != blkno %" PRId64 "\n",
   1036 				block, fd->sc_blkno);
   1037 #ifdef DDB
   1038 			 Debugger();
   1039 #endif
   1040 		 }}
   1041 #endif
   1042 		read = bp->b_flags & B_READ;
   1043 		if (read) {
   1044 			fdc->sc_fh.fh_func = floppy_read_fiq;
   1045 			fdc->sc_fh.fh_size = floppy_read_fiq_end -
   1046 			    floppy_read_fiq;
   1047 		} else {
   1048 			fdc->sc_fh.fh_func = floppy_write_fiq;
   1049 			fdc->sc_fh.fh_size = floppy_read_fiq_end -
   1050 			    floppy_read_fiq;
   1051 		}
   1052 		fdc->sc_fh.fh_flags = 0;
   1053 		fdc->sc_fh.fh_regs = &fdc->sc_fr;
   1054 		fdc->sc_fr.fr_r9 = IOMD_BASE + (IOMD_FIQRQ << 2);
   1055 		fdc->sc_fr.fr_r10 = fd->sc_nbytes;
   1056 		fdc->sc_fr.fr_r11 =
   1057 		    (u_int)((uintptr_t)bp->b_data + fd->sc_skip);
   1058 		fdc->sc_fr.fr_r12 = fdc->sc_drq;
   1059 #ifdef FD_DEBUG
   1060 		printf("fdc-doio:r9=%x r10=%x r11=%x r12=%x data=%x skip=%x\n",
   1061 		    fdc->sc_fr.fr_r9, fdc->sc_fr.fh_r10, fdc->sc_fr.fh_r11,
   1062 		    fdc->sc_fr.fh_r12, (u_int)bp->b_data, fd->sc_skip);
   1063 #endif
   1064 		if (fiq_claim(&fdc->sc_fh) == -1)
   1065 			panic("%s: Cannot claim FIQ vector", fdc->sc_dev.dv_xname);
   1066 		IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x01);
   1067 		bus_space_write_2(iot, ioh, fdctl, type->rate);
   1068 #ifdef FD_DEBUG
   1069 		printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
   1070 			read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
   1071 			head, sec, nblks);
   1072 #endif
   1073 		if (finfo) {
   1074 			/* formatting */
   1075 			if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) {
   1076 				fdc->sc_errors = 4;
   1077 				fdcretry(fdc);
   1078 				goto loop;
   1079 			}
   1080 			out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1081 			out_fdc(iot, ioh, finfo->fd_formb_secshift);
   1082 			out_fdc(iot, ioh, finfo->fd_formb_nsecs);
   1083 			out_fdc(iot, ioh, finfo->fd_formb_gaplen);
   1084 			out_fdc(iot, ioh, finfo->fd_formb_fillbyte);
   1085 		} else {
   1086 			if (read)
   1087 				out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
   1088 			else
   1089 				out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
   1090 			out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1091 			out_fdc(iot, ioh, fd->sc_cylin); /* track */
   1092 			out_fdc(iot, ioh, head);
   1093 			out_fdc(iot, ioh, sec + 1);	 /* sector +1 */
   1094 			out_fdc(iot, ioh, type->secsize);/* sector size */
   1095 			out_fdc(iot, ioh, type->sectrac);/* sectors/track */
   1096 			out_fdc(iot, ioh, type->gap1);	 /* gap1 size */
   1097 			out_fdc(iot, ioh, type->datalen);/* data length */
   1098 		}
   1099 		fdc->sc_state = IOCOMPLETE;
   1100 
   1101 		disk_busy(&fd->sc_dk);
   1102 
   1103 		/* allow 2 seconds for operation */
   1104 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1105 		return 1;				/* will return later */
   1106 
   1107 	case SEEKWAIT:
   1108 		callout_stop(&fdc->sc_timo_ch);
   1109 		fdc->sc_state = SEEKCOMPLETE;
   1110 		/* allow 1/50 second for heads to settle */
   1111 #if 0
   1112 		callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
   1113 #endif
   1114 		return 1;
   1115 
   1116 	case SEEKCOMPLETE:
   1117 		/* no data on seek */
   1118 		disk_unbusy(&fd->sc_dk, 0, 0);
   1119 
   1120 		/* Make sure seek really happened. */
   1121 		out_fdc(iot, ioh, NE7CMD_SENSEI);
   1122 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
   1123 		    cyl != bp->b_cylinder * fd->sc_type->step) {
   1124 #ifdef FD_DEBUG
   1125 			fdcstatus(&fd->sc_dev, 2, "seek failed");
   1126 #endif
   1127 			fdcretry(fdc);
   1128 			goto loop;
   1129 		}
   1130 		fd->sc_cylin = bp->b_cylinder;
   1131 		goto doio;
   1132 
   1133 	case IOTIMEDOUT:
   1134 		fiq_release(&fdc->sc_fh);
   1135 		IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
   1136 	case SEEKTIMEDOUT:
   1137 	case RECALTIMEDOUT:
   1138 	case RESETTIMEDOUT:
   1139 		fdcretry(fdc);
   1140 		goto loop;
   1141 
   1142 	case IOCOMPLETE: /* IO DONE, post-analyze */
   1143 		callout_stop(&fdc->sc_timo_ch);
   1144 
   1145 		disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
   1146 		    (bp->b_flags & B_READ));
   1147 
   1148 		if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) {
   1149 			fiq_release(&fdc->sc_fh);
   1150 			IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
   1151 #ifdef FD_DEBUG
   1152 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
   1153 			    "read failed" : "write failed");
   1154 			printf("blkno %d nblks %d\n",
   1155 			    fd->sc_blkno, fd->sc_nblks);
   1156 #endif
   1157 			fdcretry(fdc);
   1158 			goto loop;
   1159 		}
   1160 		fiq_release(&fdc->sc_fh);
   1161 		IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
   1162 		if (fdc->sc_errors) {
   1163 #if 0
   1164 			diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
   1165 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
   1166 			printf("\n");
   1167 #endif
   1168 			fdc->sc_errors = 0;
   1169 		}
   1170 		fd->sc_blkno += fd->sc_nblks;
   1171 		fd->sc_skip += fd->sc_nbytes;
   1172 		fd->sc_bcount -= fd->sc_nbytes;
   1173 		if (!finfo && fd->sc_bcount > 0) {
   1174 			bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
   1175 			goto doseek;
   1176 		}
   1177 		fdfinish(fd, bp);
   1178 		goto loop;
   1179 
   1180 	case DORESET:
   1181 		/* try a reset, keep motor on */
   1182 		fd_set_motor(fdc, 1);
   1183 		delay(100);
   1184 		fd_set_motor(fdc, 0);
   1185 		fdc->sc_state = RESETCOMPLETE;
   1186 		callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
   1187 		return 1;			/* will return later */
   1188 
   1189 	case RESETCOMPLETE:
   1190 		callout_stop(&fdc->sc_timo_ch);
   1191 		/* clear the controller output buffer */
   1192 		for (i = 0; i < 4; i++) {
   1193 			out_fdc(iot, ioh, NE7CMD_SENSEI);
   1194 			(void) fdcresult(fdc);
   1195 		}
   1196 
   1197 		/* fall through */
   1198 	case DORECAL:
   1199 		out_fdc(iot, ioh, NE7CMD_RECAL);	/* recalibrate function */
   1200 		out_fdc(iot, ioh, fd->sc_drive);
   1201 		fdc->sc_state = RECALWAIT;
   1202 		callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
   1203 		return 1;			/* will return later */
   1204 
   1205 	case RECALWAIT:
   1206 		callout_stop(&fdc->sc_timo_ch);
   1207 		fdc->sc_state = RECALCOMPLETE;
   1208 		/* allow 1/30 second for heads to settle */
   1209 #if 0
   1210 		callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
   1211 #endif
   1212 		return 1;			/* will return later */
   1213 
   1214 	case RECALCOMPLETE:
   1215 		out_fdc(iot, ioh, NE7CMD_SENSEI);
   1216 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
   1217 #ifdef FD_DEBUG
   1218 			fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
   1219 #endif
   1220 			fdcretry(fdc);
   1221 			goto loop;
   1222 		}
   1223 		fd->sc_cylin = 0;
   1224 		goto doseek;
   1225 
   1226 	case MOTORWAIT:
   1227 		if (fd->sc_flags & FD_MOTOR_WAIT)
   1228 			return 1;		/* time's not up yet */
   1229 		goto doseek;
   1230 
   1231 	default:
   1232 		fdcstatus(&fd->sc_dev, 0, "stray interrupt");
   1233 		return 1;
   1234 	}
   1235 #ifdef DIAGNOSTIC
   1236 	panic("fdcintr: impossible");
   1237 #endif
   1238 #undef	st0
   1239 #undef	cyl
   1240 }
   1241 
   1242 void
   1243 fdcretry(fdc)
   1244 	struct fdc_softc *fdc;
   1245 {
   1246 	char bits[64];
   1247 	struct fd_softc *fd;
   1248 	struct buf *bp;
   1249 
   1250 	fd = fdc->sc_drives.tqh_first;
   1251 	bp = BUFQ_PEEK(fd->sc_q);
   1252 
   1253 	if (fd->sc_opts & FDOPT_NORETRY)
   1254 	    goto fail;
   1255 	switch (fdc->sc_errors) {
   1256 	case 0:
   1257 		/* try again */
   1258 		fdc->sc_state = DOSEEK;
   1259 		break;
   1260 
   1261 	case 1: case 2: case 3:
   1262 		/* didn't work; try recalibrating */
   1263 		fdc->sc_state = DORECAL;
   1264 		break;
   1265 
   1266 	case 4:
   1267 		/* still no go; reset the bastard */
   1268 		fdc->sc_state = DORESET;
   1269 		break;
   1270 
   1271 	default:
   1272 	fail:
   1273 		if ((fd->sc_opts & FDOPT_SILENT) == 0) {
   1274 			diskerr(bp, "fd", "hard error", LOG_PRINTF,
   1275 				fd->sc_skip / FDC_BSIZE,
   1276 				(struct disklabel *)NULL);
   1277 
   1278 			printf(" (st0 %s",
   1279 			       bitmask_snprintf(fdc->sc_status[0],
   1280 						NE7_ST0BITS, bits,
   1281 						sizeof(bits)));
   1282 			printf(" st1 %s",
   1283 			       bitmask_snprintf(fdc->sc_status[1],
   1284 						NE7_ST1BITS, bits,
   1285 						sizeof(bits)));
   1286 			printf(" st2 %s",
   1287 			       bitmask_snprintf(fdc->sc_status[2],
   1288 						NE7_ST2BITS, bits,
   1289 						sizeof(bits)));
   1290 			printf(" cyl %d head %d sec %d)\n",
   1291 			       fdc->sc_status[3],
   1292 			       fdc->sc_status[4],
   1293 			       fdc->sc_status[5]);
   1294 		}
   1295 
   1296 		bp->b_error = EIO;
   1297 		fdfinish(fd, bp);
   1298 	}
   1299 	fdc->sc_errors++;
   1300 }
   1301 
   1302 int
   1303 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
   1304 {
   1305 	struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
   1306 	struct fdformat_parms *form_parms;
   1307 	struct fdformat_cmd *form_cmd;
   1308 	struct ne7_fd_formb *fd_formb;
   1309 	struct disklabel buffer;
   1310 	int error;
   1311 	unsigned int scratch;
   1312 	int il[FD_MAX_NSEC + 1];
   1313 	register int i, j;
   1314 
   1315 	switch (cmd) {
   1316 	case DIOCGDINFO:
   1317 		memset(&buffer, 0, sizeof(buffer));
   1318 
   1319 		buffer.d_secpercyl = fd->sc_type->seccyl;
   1320 		buffer.d_type = DTYPE_FLOPPY;
   1321 		buffer.d_secsize = FDC_BSIZE;
   1322 
   1323 		if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
   1324 			return EINVAL;
   1325 
   1326 		*(struct disklabel *)addr = buffer;
   1327 		return 0;
   1328 
   1329 	case DIOCWLABEL:
   1330 		if ((flag & FWRITE) == 0)
   1331 			return EBADF;
   1332 		/* XXX do something */
   1333 		return 0;
   1334 
   1335 	case DIOCWDINFO:
   1336 		if ((flag & FWRITE) == 0)
   1337 			return EBADF;
   1338 
   1339 		error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
   1340 		if (error)
   1341 			return error;
   1342 
   1343 		error = writedisklabel(dev, fdstrategy, &buffer, NULL);
   1344 		return error;
   1345 
   1346 	case FDIOCGETFORMAT:
   1347 		form_parms = (struct fdformat_parms *)addr;
   1348 		form_parms->fdformat_version = FDFORMAT_VERSION;
   1349 		form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
   1350 		form_parms->ncyl = fd->sc_type->cyls;
   1351 		form_parms->nspt = fd->sc_type->sectrac;
   1352 		form_parms->ntrk = fd->sc_type->heads;
   1353 		form_parms->stepspercyl = fd->sc_type->step;
   1354 		form_parms->gaplen = fd->sc_type->gap2;
   1355 		form_parms->fillbyte = fd->sc_type->fillbyte;
   1356 		form_parms->interleave = fd->sc_type->interleave;
   1357 		switch (fd->sc_type->rate) {
   1358 		case FDC_500KBPS:
   1359 			form_parms->xfer_rate = 500 * 1024;
   1360 			break;
   1361 		case FDC_300KBPS:
   1362 			form_parms->xfer_rate = 300 * 1024;
   1363 			break;
   1364 		case FDC_250KBPS:
   1365 			form_parms->xfer_rate = 250 * 1024;
   1366 			break;
   1367 		default:
   1368 			return EINVAL;
   1369 		}
   1370 		return 0;
   1371 
   1372 	case FDIOCSETFORMAT:
   1373 		if((flag & FWRITE) == 0)
   1374 			return EBADF;	/* must be opened for writing */
   1375 		form_parms = (struct fdformat_parms *)addr;
   1376 		if (form_parms->fdformat_version != FDFORMAT_VERSION)
   1377 			return EINVAL;	/* wrong version of formatting prog */
   1378 
   1379 		scratch = form_parms->nbps >> 7;
   1380 		if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
   1381 		    scratch & ~(1 << (ffs(scratch)-1)))
   1382 			/* not a power-of-two multiple of 128 */
   1383 			return EINVAL;
   1384 
   1385 		switch (form_parms->xfer_rate) {
   1386 		case 500 * 1024:
   1387 			fd->sc_type->rate = FDC_500KBPS;
   1388 			break;
   1389 		case 300 * 1024:
   1390 			fd->sc_type->rate = FDC_300KBPS;
   1391 			break;
   1392 		case 250 * 1024:
   1393 			fd->sc_type->rate = FDC_250KBPS;
   1394 			break;
   1395 		default:
   1396 			return EINVAL;
   1397 		}
   1398 
   1399 		if (form_parms->nspt > FD_MAX_NSEC ||
   1400 		    form_parms->fillbyte > 0xff ||
   1401 		    form_parms->interleave > 0xff)
   1402 			return EINVAL;
   1403 		fd->sc_type->sectrac = form_parms->nspt;
   1404 		if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
   1405 			return EINVAL;
   1406 		fd->sc_type->heads = form_parms->ntrk;
   1407 		fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
   1408 		fd->sc_type->secsize = ffs(scratch)-1;
   1409 		fd->sc_type->gap2 = form_parms->gaplen;
   1410 		fd->sc_type->cyls = form_parms->ncyl;
   1411 		fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
   1412 			form_parms->nbps / DEV_BSIZE;
   1413 		fd->sc_type->step = form_parms->stepspercyl;
   1414 		fd->sc_type->fillbyte = form_parms->fillbyte;
   1415 		fd->sc_type->interleave = form_parms->interleave;
   1416 		return 0;
   1417 
   1418 	case FDIOCFORMAT_TRACK:
   1419 		if((flag & FWRITE) == 0)
   1420 			return EBADF;	/* must be opened for writing */
   1421 		form_cmd = (struct fdformat_cmd *)addr;
   1422 		if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
   1423 			return EINVAL;	/* wrong version of formatting prog */
   1424 
   1425 		if (form_cmd->head >= fd->sc_type->heads ||
   1426 		    form_cmd->cylinder >= fd->sc_type->cyls) {
   1427 			return EINVAL;
   1428 		}
   1429 
   1430 		fd_formb = malloc(sizeof(struct ne7_fd_formb),
   1431 		    M_TEMP, M_NOWAIT);
   1432 		if(fd_formb == 0)
   1433 			return ENOMEM;
   1434 
   1435 
   1436 		fd_formb->head = form_cmd->head;
   1437 		fd_formb->cyl = form_cmd->cylinder;
   1438 		fd_formb->transfer_rate = fd->sc_type->rate;
   1439 		fd_formb->fd_formb_secshift = fd->sc_type->secsize;
   1440 		fd_formb->fd_formb_nsecs = fd->sc_type->sectrac;
   1441 		fd_formb->fd_formb_gaplen = fd->sc_type->gap2;
   1442 		fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte;
   1443 
   1444 		memset(il, 0, sizeof il);
   1445 		for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) {
   1446 			while (il[(j%fd_formb->fd_formb_nsecs)+1])
   1447 				j++;
   1448 			il[(j%fd_formb->fd_formb_nsecs)+1] = i;
   1449 			j += fd->sc_type->interleave;
   1450 		}
   1451 		for (i = 0; i < fd_formb->fd_formb_nsecs; i++) {
   1452 			fd_formb->fd_formb_cylno(i) = form_cmd->cylinder;
   1453 			fd_formb->fd_formb_headno(i) = form_cmd->head;
   1454 			fd_formb->fd_formb_secno(i) = il[i+1];
   1455 			fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize;
   1456 		}
   1457 
   1458 		error = fdformat(dev, fd_formb, l);
   1459 		free(fd_formb, M_TEMP);
   1460 		return error;
   1461 
   1462 	case FDIOCGETOPTS:		/* get drive options */
   1463 		*(int *)addr = fd->sc_opts;
   1464 		return 0;
   1465 
   1466 	case FDIOCSETOPTS:		/* set drive options */
   1467 		fd->sc_opts = *(int *)addr;
   1468 		return 0;
   1469 
   1470 	default:
   1471 		return ENOTTY;
   1472 	}
   1473 
   1474 #ifdef DIAGNOSTIC
   1475 	panic("fdioctl: impossible");
   1476 #endif
   1477 }
   1478 
   1479 int
   1480 fdformat(dev_t dev, struct ne7_fd_formb *finfo, struct lwp *l)
   1481 {
   1482 	int rv = 0;
   1483 	struct fd_softc *fd = device_lookup_private(&fd_cd,FDUNIT(dev));
   1484 	struct fd_type *type = fd->sc_type;
   1485 	struct buf *bp;
   1486 
   1487 	/* set up a buffer header for fdstrategy() */
   1488 	bp = getiobuf(NULL, false);
   1489 	if(bp == 0)
   1490 		return ENOBUFS;
   1491 	bp->b_flags = B_PHYS | B_FORMAT;
   1492 	bp->b_cflags |= BC_BUSY;
   1493 	bp->b_proc = l->l_proc;
   1494 	bp->b_dev = dev;
   1495 
   1496 	/*
   1497 	 * calculate a fake blkno, so fdstrategy() would initiate a
   1498 	 * seek to the requested cylinder
   1499 	 */
   1500 	bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
   1501 		       + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
   1502 
   1503 	bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
   1504 	bp->b_data = (void *)finfo;
   1505 
   1506 #ifdef DEBUG
   1507 	printf("fdformat: blkno %llx count %lx\n",
   1508 	    (unsigned long long)bp->b_blkno, bp->b_bcount);
   1509 #endif
   1510 
   1511 	/* now do the format */
   1512 	fdstrategy(bp);
   1513 
   1514 	/* ...and wait for it to complete */
   1515 	/* XXX very dodgy */
   1516 	mutex_enter(bp->b_objlock);
   1517 	while (!(bp->b_oflags & BO_DONE)) {
   1518 		rv = cv_timedwait(&bp->b_done, bp->b_objlock, 20 * hz);
   1519 		if (rv == EWOULDBLOCK)
   1520 			break;
   1521 	}
   1522 	mutex_exit(bp->b_objlock);
   1523 
   1524 	if (rv == EWOULDBLOCK) {
   1525 		/* timed out */
   1526 		rv = EIO;
   1527 		biodone(bp);
   1528 	} else if (bp->b_error != 0)
   1529 		rv = bp->b_error;
   1530 	putiobuf(bp);
   1531 	return rv;
   1532 }
   1533 
   1534 #include "md.h"
   1535 #if NMD > 0
   1536 
   1537 #include <dev/md.h>
   1538 
   1539 int load_memory_disc_from_floppy __P((struct md_conf *md, dev_t dev));
   1540 
   1541 int
   1542 load_memory_disc_from_floppy(md, dev)
   1543 	struct md_conf *md;
   1544 	dev_t dev;
   1545 {
   1546 	struct buf *bp;
   1547 	int loop;
   1548 	int s;
   1549 	int type;
   1550 	int floppysize;
   1551 
   1552 	if (bdevsw_lookup(dev) != &fd_bdevsw)
   1553 		return(EINVAL);
   1554 
   1555 	if (md->md_type == MD_UNCONFIGURED || md->md_addr == 0)
   1556 		return(EBUSY);
   1557 
   1558 	type = FDTYPE(dev) - 1;
   1559 	if (type < 0) type = 0;
   1560 	floppysize = fd_types[type].size << (fd_types[type].secsize + 7);
   1561 
   1562 	if (md->md_size < floppysize) {
   1563 		printf("Memory disc is not big enough for floppy image\n");
   1564 		return(EINVAL);
   1565 	}
   1566 
   1567 /* We have the memory disk ! */
   1568 
   1569 	printf("Loading memory disc : %4dK ", 0);
   1570 
   1571 /* obtain a buffer */
   1572 
   1573 	bp = geteblk(fd_types[type].sectrac * DEV_BSIZE);
   1574 
   1575 /* request no partition relocation by driver on I/O operations */
   1576 
   1577 	bp->b_dev = dev;
   1578 
   1579 	s = spl0();
   1580 
   1581 	if (fdopen(bp->b_dev, 0, 0, curlwp) != 0) {
   1582 		brelse(bp, 0);
   1583 		printf("Cannot open floppy device\n");
   1584 			return(EINVAL);
   1585 	}
   1586 
   1587 	for (loop = 0;
   1588 	    loop < (floppysize / DEV_BSIZE / fd_types[type].sectrac);
   1589 	    ++loop) {
   1590 		printf("\x08\x08\x08\x08\x08\x08%4dK ",
   1591 		    loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
   1592 		bp->b_blkno = loop * fd_types[type].sectrac;
   1593 		bp->b_bcount = fd_types[type].sectrac * DEV_BSIZE;
   1594 		bp->b_flags |= B_READ;
   1595 		bp->b_error = 0;
   1596 		bp->b_resid = 0;
   1597 		fdstrategy(bp);
   1598 
   1599 		if (biowait(bp))
   1600 			panic("Cannot load floppy image");
   1601 
   1602 		memcpy((char *)md->md_addr + loop * fd_types[type].sectrac
   1603 		    * DEV_BSIZE, (void *)bp->b_data,
   1604 		    fd_types[type].sectrac * DEV_BSIZE);
   1605 	}
   1606 	printf("\x08\x08\x08\x08\x08\x08%4dK done\n",
   1607 	    loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
   1608 
   1609 	fdclose(bp->b_dev, 0, 0, curlwp);
   1610 
   1611 	brelse(bp, 0);
   1612 
   1613 	splx(s);
   1614 	return(0);
   1615 }
   1616 
   1617 #endif
   1618