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