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