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