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