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