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