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