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