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