Home | History | Annotate | Line # | Download | only in mainbus
fd.c revision 1.23
      1 /*	$NetBSD: fd.c,v 1.23 2005/12/24 20:06:46 perry 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.23 2005/12/24 20:06:46 perry 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 /* XXX misuse a flag to identify format operation */
    139 #define B_FORMAT B_XXX
    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);
    403 	callout_init(&fdc->sc_intr_ch);
    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 (fdc->sc_dev.dv_unit == 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);
    503 	callout_init(&fd->sc_motoroff_ch);
    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 	fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
    523 	fd->sc_dk.dk_driver = &fddkdriver;
    524 	disk_attach(&fd->sc_dk);
    525 
    526 	/* Needed to power off if the motor is on when we halt. */
    527 
    528 }
    529 
    530 /*
    531  * Translate nvram type into internal data structure.  Return NULL for
    532  * none/unknown/unusable.
    533  */
    534 struct fd_type *
    535 fd_nvtotype(fdc, nvraminfo, drive)
    536 	char *fdc;
    537 	int nvraminfo, drive;
    538 {
    539 	int type;
    540 
    541 	type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0;
    542 	switch (type) {
    543 #ifndef RC7500
    544 	case 0x00 :
    545 		return NULL;
    546 #else
    547 	case 0x00 :
    548 #endif	/* !RC7500 */
    549 	case 0x10 :
    550 		return &fd_types[0];
    551 	default:
    552 		printf("%s: drive %d: unknown device type 0x%x\n",
    553 		    fdc, drive, type);
    554 		return NULL;
    555 	}
    556 }
    557 
    558 inline struct fd_type *
    559 fd_dev_to_type(fd, dev)
    560 	struct fd_softc *fd;
    561 	dev_t dev;
    562 {
    563 	int type = FDTYPE(dev);
    564 
    565 	if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
    566 		return NULL;
    567 	return type ? &fd_types[type - 1] : fd->sc_deftype;
    568 }
    569 
    570 void
    571 fdstrategy(bp)
    572 	register struct buf *bp;	/* IO operation to perform */
    573 {
    574 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(bp->b_dev)];
    575 	int sz;
    576  	int s;
    577 
    578 	/* Valid unit, controller, and request? */
    579 	if (bp->b_blkno < 0 ||
    580 	    ((bp->b_bcount % FDC_BSIZE) != 0 &&
    581 	     (bp->b_flags & B_FORMAT) == 0)) {
    582 		bp->b_error = EINVAL;
    583 		goto bad;
    584 	}
    585 
    586 	/* If it's a null transfer, return immediately. */
    587 	if (bp->b_bcount == 0)
    588 		goto done;
    589 
    590 	sz = howmany(bp->b_bcount, FDC_BSIZE);
    591 
    592 	if (bp->b_blkno + sz > fd->sc_type->size) {
    593 		sz = fd->sc_type->size - bp->b_blkno;
    594 		if (sz == 0) {
    595 			/* If exactly at end of disk, return EOF. */
    596 			goto done;
    597 		}
    598 		if (sz < 0) {
    599 			/* If past end of disk, return EINVAL. */
    600 			bp->b_error = EINVAL;
    601 			goto bad;
    602 		}
    603 		/* Otherwise, truncate request. */
    604 		bp->b_bcount = sz << DEV_BSHIFT;
    605 	}
    606 
    607 	bp->b_rawblkno = bp->b_blkno;
    608  	bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl;
    609 
    610 #ifdef FD_DEBUG
    611 	printf("fdstrategy: b_blkno %d b_bcount %d blkno %d cylin %d sz %d\n",
    612 	    bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylinder, sz);
    613 #endif
    614 
    615 	/* Queue transfer on drive, activate drive and controller if idle. */
    616 	s = splbio();
    617 	BUFQ_PUT(fd->sc_q, bp);
    618 	callout_stop(&fd->sc_motoroff_ch);		/* a good idea */
    619 	if (fd->sc_active == 0)
    620 		fdstart(fd);
    621 #ifdef DIAGNOSTIC
    622 	else {
    623 		struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    624 		if (fdc->sc_state == DEVIDLE) {
    625 			printf("fdstrategy: controller inactive\n");
    626 			fdcstart(fdc);
    627 		}
    628 	}
    629 #endif
    630 	splx(s);
    631 	return;
    632 
    633 bad:
    634 	bp->b_flags |= B_ERROR;
    635 done:
    636 	/* Toss transfer; we're done early. */
    637 	bp->b_resid = bp->b_bcount;
    638 	biodone(bp);
    639 }
    640 
    641 void
    642 fdstart(fd)
    643 	struct fd_softc *fd;
    644 {
    645 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    646 	int active = fdc->sc_drives.tqh_first != 0;
    647 
    648 	/* Link into controller queue. */
    649 	fd->sc_active = 1;
    650 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    651 
    652 	/* If controller not already active, start it. */
    653 	if (!active)
    654 		fdcstart(fdc);
    655 }
    656 
    657 void
    658 fdfinish(fd, bp)
    659 	struct fd_softc *fd;
    660 	struct buf *bp;
    661 {
    662 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    663 
    664 	/*
    665 	 * Move this drive to the end of the queue to give others a `fair'
    666 	 * chance.  We only force a switch if N operations are completed while
    667 	 * another drive is waiting to be serviced, since there is a long motor
    668 	 * startup delay whenever we switch.
    669 	 */
    670 	(void)BUFQ_GET(fd->sc_q);
    671 	if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
    672 		fd->sc_ops = 0;
    673 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
    674 		if (BUFQ_PEEK(fd->sc_q) != NULL)
    675 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    676 		else
    677 			fd->sc_active = 0;
    678 	}
    679 	bp->b_resid = fd->sc_bcount;
    680 	fd->sc_skip = 0;
    681 
    682 	biodone(bp);
    683 	/* turn off motor 5s from now */
    684 	callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
    685 	fdc->sc_state = DEVIDLE;
    686 }
    687 
    688 int
    689 fdread(dev, uio, flags)
    690 	dev_t dev;
    691 	struct uio *uio;
    692 	int flags;
    693 {
    694 
    695 	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
    696 }
    697 
    698 int
    699 fdwrite(dev, uio, flags)
    700 	dev_t dev;
    701 	struct uio *uio;
    702 	int flags;
    703 {
    704 
    705 	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
    706 }
    707 
    708 void
    709 fd_set_motor(fdc, reset)
    710 	struct fdc_softc *fdc;
    711 	int reset;
    712 {
    713 	struct fd_softc *fd;
    714 	u_char status;
    715 	int n;
    716 
    717 	if ((fd = fdc->sc_drives.tqh_first) != NULL)
    718 		status = fd->sc_drive;
    719 	else
    720 		status = 0;
    721 	if (!reset)
    722 		status |= FDO_FRST | FDO_FDMAEN;
    723 	for (n = 0; n < 4; n++)
    724 		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
    725 			status |= FDO_MOEN(n);
    726 	bus_space_write_2(fdc->sc_iot, fdc->sc_ioh, fdout, status);
    727 }
    728 
    729 void
    730 fd_motor_off(arg)
    731 	void *arg;
    732 {
    733 	struct fd_softc *fd = arg;
    734 	int s;
    735 
    736 	s = splbio();
    737 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
    738 	fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0);
    739 	splx(s);
    740 }
    741 
    742 void
    743 fd_motor_on(arg)
    744 	void *arg;
    745 {
    746 	struct fd_softc *fd = arg;
    747 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    748 	int s;
    749 
    750 	s = splbio();
    751 	fd->sc_flags &= ~FD_MOTOR_WAIT;
    752 	if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
    753 		(void) fdcintr(fdc);
    754 	splx(s);
    755 }
    756 
    757 int
    758 fdcresult(fdc)
    759 	struct fdc_softc *fdc;
    760 {
    761 	bus_space_tag_t iot = fdc->sc_iot;
    762 	bus_space_handle_t ioh = fdc->sc_ioh;
    763 	u_char i;
    764 	int j = 100000,
    765 	    n = 0;
    766 
    767 	for (; j; j--) {
    768 		i = bus_space_read_1(iot, ioh, fdsts) &
    769 		    (NE7_DIO | NE7_RQM | NE7_CB);
    770 		if (i == NE7_RQM)
    771 			return n;
    772 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
    773 			if (n >= sizeof(fdc->sc_status)) {
    774 				log(LOG_ERR, "fdcresult: overrun\n");
    775 				return -1;
    776 			}
    777 			fdc->sc_status[n++] =
    778 			    bus_space_read_1(iot, ioh, fddata);
    779 		}
    780 		delay(10);
    781 	}
    782 	log(LOG_ERR, "fdcresult: timeout\n");
    783 	return -1;
    784 }
    785 
    786 int
    787 out_fdc(iot, ioh, x)
    788 	bus_space_tag_t iot;
    789 	bus_space_handle_t ioh;
    790 	u_char x;
    791 {
    792 	int i = 100000;
    793 
    794 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
    795 	if (i <= 0)
    796 		return -1;
    797 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
    798 	if (i <= 0)
    799 		return -1;
    800 	bus_space_write_2(iot, ioh, fddata, x);
    801 	return 0;
    802 }
    803 
    804 int
    805 fdopen(dev, flags, mode, l)
    806 	dev_t dev;
    807 	int flags;
    808 	int mode;
    809 	struct lwp *l;
    810 {
    811  	int unit;
    812 	struct fd_softc *fd;
    813 	struct fd_type *type;
    814 
    815 	unit = FDUNIT(dev);
    816 	if (unit >= fd_cd.cd_ndevs)
    817 		return ENXIO;
    818 	fd = fd_cd.cd_devs[unit];
    819 	if (fd == 0)
    820 		return ENXIO;
    821 	type = fd_dev_to_type(fd, dev);
    822 	if (type == NULL)
    823 		return ENXIO;
    824 
    825 	if ((fd->sc_flags & FD_OPEN) != 0 &&
    826 	    memcmp(fd->sc_type, type, sizeof(*type)))
    827 		return EBUSY;
    828 
    829 	fd->sc_type_copy = *type;
    830 	fd->sc_type = &fd->sc_type_copy;
    831 	fd->sc_cylin = -1;
    832 	fd->sc_flags |= FD_OPEN;
    833 
    834 	return 0;
    835 }
    836 
    837 int
    838 fdclose(dev, flags, mode, l)
    839 	dev_t dev;
    840 	int flags;
    841 	int mode;
    842 	struct lwp *l;
    843 {
    844 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
    845 
    846 	fd->sc_flags &= ~FD_OPEN;
    847 	fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT);
    848 	return 0;
    849 }
    850 
    851 void
    852 fdcstart(fdc)
    853 	struct fdc_softc *fdc;
    854 {
    855 
    856 #ifdef DIAGNOSTIC
    857 	/* only got here if controller's drive queue was inactive; should
    858 	   be in idle state */
    859 	if (fdc->sc_state != DEVIDLE) {
    860 		printf("fdcstart: not idle\n");
    861 		return;
    862 	}
    863 #endif
    864 	(void) fdcintr(fdc);
    865 }
    866 
    867 void
    868 fdcstatus(dv, n, s)
    869 	struct device *dv;
    870 	int n;
    871 	const char *s;
    872 {
    873 	struct fdc_softc *fdc = (void *)dv->dv_parent;
    874 	char bits[64];
    875 
    876 	if (n == 0) {
    877 		out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
    878 		(void) fdcresult(fdc);
    879 		n = 2;
    880 	}
    881 
    882 	printf("%s: %s", dv->dv_xname, s);
    883 
    884 	switch (n) {
    885 	case 0:
    886 		printf("\n");
    887 		break;
    888 	case 2:
    889 		printf(" (st0 %s cyl %d)\n",
    890 		    bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
    891 		    bits, sizeof(bits)), fdc->sc_status[1]);
    892 		break;
    893 	case 7:
    894 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
    895 		    NE7_ST0BITS, bits, sizeof(bits)));
    896 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
    897 		    NE7_ST1BITS, bits, sizeof(bits)));
    898 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
    899 		    NE7_ST2BITS, bits, sizeof(bits)));
    900 		printf(" cyl %d head %d sec %d)\n",
    901 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
    902 		break;
    903 #ifdef DIAGNOSTIC
    904 	default:
    905 		printf("\nfdcstatus: weird size");
    906 		break;
    907 #endif
    908 	}
    909 }
    910 
    911 void
    912 fdctimeout(arg)
    913 	void *arg;
    914 {
    915 	struct fdc_softc *fdc = arg;
    916 	struct fd_softc *fd = fdc->sc_drives.tqh_first;
    917 	int s;
    918 
    919 	s = splbio();
    920 #ifdef DEBUG
    921 	log(LOG_ERR,"fdctimeout: state %d\n", fdc->sc_state);
    922 #endif
    923 	fdcstatus(&fd->sc_dev, 0, "timeout");
    924 
    925 	if (BUFQ_PEEK(fd->sc_q) != NULL)
    926 		fdc->sc_state++;
    927 	else
    928 		fdc->sc_state = DEVIDLE;
    929 
    930 	(void) fdcintr(fdc);
    931 	splx(s);
    932 }
    933 
    934 void
    935 fdcpseudointr(arg)
    936 	void *arg;
    937 {
    938 	int s;
    939 
    940 	/* Just ensure it has the right spl. */
    941 	s = splbio();
    942 	(void) fdcintr(arg);
    943 	splx(s);
    944 }
    945 
    946 int
    947 fdcintr(arg)
    948 	void *arg;
    949 {
    950 	struct fdc_softc *fdc = arg;
    951 #define	st0	fdc->sc_status[0]
    952 #define	cyl	fdc->sc_status[1]
    953 	struct fd_softc *fd;
    954 	struct buf *bp;
    955 	bus_space_tag_t iot = fdc->sc_iot;
    956 	bus_space_handle_t ioh = fdc->sc_ioh;
    957 	int read, head, sec, i, nblks;
    958 	struct fd_type *type;
    959 	struct ne7_fd_formb *finfo = NULL;
    960 
    961 loop:
    962 	/* Is there a drive for the controller to do a transfer with? */
    963 	fd = fdc->sc_drives.tqh_first;
    964 	if (fd == NULL) {
    965 		fdc->sc_state = DEVIDLE;
    966  		return 1;
    967 	}
    968 
    969 	/* Is there a transfer to this drive?  If not, deactivate drive. */
    970 	bp = BUFQ_PEEK(fd->sc_q);
    971 	if (bp == NULL) {
    972 		fd->sc_ops = 0;
    973 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
    974 		fd->sc_active = 0;
    975 		goto loop;
    976 	}
    977 
    978 	if (bp->b_flags & B_FORMAT)
    979 		finfo = (struct ne7_fd_formb *)bp->b_data;
    980 
    981 	switch (fdc->sc_state) {
    982 	case DEVIDLE:
    983 		fdc->sc_errors = 0;
    984 		fd->sc_skip = 0;
    985 		fd->sc_bcount = bp->b_bcount;
    986 		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
    987 		callout_stop(&fd->sc_motoroff_ch);
    988 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
    989 			fdc->sc_state = MOTORWAIT;
    990 			return 1;
    991 		}
    992 		if ((fd->sc_flags & FD_MOTOR) == 0) {
    993 			/* Turn on the motor, being careful about pairing. */
    994 			struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
    995 			if (ofd && ofd->sc_flags & FD_MOTOR) {
    996 				callout_stop(&ofd->sc_motoroff_ch);
    997 				ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
    998 			}
    999 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
   1000 			fd_set_motor(fdc, 0);
   1001 			fdc->sc_state = MOTORWAIT;
   1002 			/* Allow .25s for motor to stabilize. */
   1003 			callout_reset(&fd->sc_motoron_ch, hz / 4,
   1004 			    fd_motor_on, fd);
   1005 			return 1;
   1006 		}
   1007 		/* Make sure the right drive is selected. */
   1008 		fd_set_motor(fdc, 0);
   1009 
   1010 		/* fall through */
   1011 	case DOSEEK:
   1012 	doseek:
   1013 		if (fd->sc_cylin == bp->b_cylinder)
   1014 			goto doio;
   1015 
   1016 #if 1
   1017 		out_fdc(iot, ioh, NE7CMD_CONFIGURE);/* configure command */
   1018 		out_fdc(iot, ioh, 0);
   1019 		out_fdc(iot, ioh, 0x18);
   1020 		out_fdc(iot, ioh, 0);
   1021 #endif
   1022 		out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
   1023 		out_fdc(iot, ioh, fd->sc_type->steprate);
   1024 		out_fdc(iot, ioh, 6);		/* XXX head load time == 6ms */
   1025 
   1026 		out_fdc(iot, ioh, NE7CMD_SEEK);	/* seek function */
   1027 		out_fdc(iot, ioh, fd->sc_drive);	/* drive number */
   1028 		out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
   1029 
   1030 		fd->sc_cylin = -1;
   1031 		fdc->sc_state = SEEKWAIT;
   1032 
   1033 		fd->sc_dk.dk_seek++;
   1034 		disk_busy(&fd->sc_dk);
   1035 
   1036 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
   1037 		return 1;
   1038 
   1039 	case DOIO:
   1040 	doio:
   1041 		type = fd->sc_type;
   1042 		if (finfo)
   1043 			fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
   1044 				      (char *)finfo;
   1045 		sec = fd->sc_blkno % type->seccyl;
   1046 		nblks = type->seccyl - sec;
   1047 		nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
   1048 		nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
   1049 		fd->sc_nblks = nblks;
   1050 		fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
   1051 		head = sec / type->sectrac;
   1052 		sec -= head * type->sectrac;
   1053 #ifdef DIAGNOSTIC
   1054 		{daddr_t  block;
   1055 		 block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec;
   1056 		 if (block != fd->sc_blkno) {
   1057 			 printf("fdcintr: block %" PRId64
   1058 			     " != blkno %" PRId64 "\n",
   1059 				block, fd->sc_blkno);
   1060 #ifdef DDB
   1061 			 Debugger();
   1062 #endif
   1063 		 }}
   1064 #endif
   1065 		read = bp->b_flags & B_READ;
   1066 		if (read) {
   1067 			fdc->sc_fh.fh_func = floppy_read_fiq;
   1068 			fdc->sc_fh.fh_size = floppy_read_fiq_end -
   1069 			    floppy_read_fiq;
   1070 		} else {
   1071 			fdc->sc_fh.fh_func = floppy_write_fiq;
   1072 			fdc->sc_fh.fh_size = floppy_read_fiq_end -
   1073 			    floppy_read_fiq;
   1074 		}
   1075 		fdc->sc_fh.fh_flags = 0;
   1076 		fdc->sc_fh.fh_regs = &fdc->sc_fr;
   1077 		fdc->sc_fr.fr_r9 = IOMD_BASE + (IOMD_FIQRQ << 2);
   1078 		fdc->sc_fr.fr_r10 = fd->sc_nbytes;
   1079 		fdc->sc_fr.fr_r11 = (u_int)(bp->b_data + fd->sc_skip);
   1080 		fdc->sc_fr.fr_r12 = fdc->sc_drq;
   1081 #ifdef FD_DEBUG
   1082 		printf("fdc-doio:r9=%x r10=%x r11=%x r12=%x data=%x skip=%x\n",
   1083 		    fdc->sc_fr.fr_r9, fdc->sc_fr.fh_r10, fdc->sc_fr.fh_r11,
   1084 		    fdc->sc_fr.fh_r12, (u_int)bp->b_data, fd->sc_skip);
   1085 #endif
   1086 		if (fiq_claim(&fdc->sc_fh) == -1)
   1087 			panic("%s: Cannot claim FIQ vector", fdc->sc_dev.dv_xname);
   1088 		IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x01);
   1089 		bus_space_write_2(iot, ioh, fdctl, type->rate);
   1090 #ifdef FD_DEBUG
   1091 		printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
   1092 			read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
   1093 			head, sec, nblks);
   1094 #endif
   1095 		if (finfo) {
   1096 			/* formatting */
   1097 			if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) {
   1098 				fdc->sc_errors = 4;
   1099 				fdcretry(fdc);
   1100 				goto loop;
   1101 			}
   1102 			out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1103 			out_fdc(iot, ioh, finfo->fd_formb_secshift);
   1104 			out_fdc(iot, ioh, finfo->fd_formb_nsecs);
   1105 			out_fdc(iot, ioh, finfo->fd_formb_gaplen);
   1106 			out_fdc(iot, ioh, finfo->fd_formb_fillbyte);
   1107 		} else {
   1108 			if (read)
   1109 				out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
   1110 			else
   1111 				out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
   1112 			out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1113 			out_fdc(iot, ioh, fd->sc_cylin); /* track */
   1114 			out_fdc(iot, ioh, head);
   1115 			out_fdc(iot, ioh, sec + 1);	 /* sector +1 */
   1116 			out_fdc(iot, ioh, type->secsize);/* sector size */
   1117 			out_fdc(iot, ioh, type->sectrac);/* sectors/track */
   1118 			out_fdc(iot, ioh, type->gap1);	 /* gap1 size */
   1119 			out_fdc(iot, ioh, type->datalen);/* data length */
   1120 		}
   1121 		fdc->sc_state = IOCOMPLETE;
   1122 
   1123 		disk_busy(&fd->sc_dk);
   1124 
   1125 		/* allow 2 seconds for operation */
   1126 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1127 		return 1;				/* will return later */
   1128 
   1129 	case SEEKWAIT:
   1130 		callout_stop(&fdc->sc_timo_ch);
   1131 		fdc->sc_state = SEEKCOMPLETE;
   1132 		/* allow 1/50 second for heads to settle */
   1133 #if 0
   1134 		callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
   1135 #endif
   1136 		return 1;
   1137 
   1138 	case SEEKCOMPLETE:
   1139 		/* no data on seek */
   1140 		disk_unbusy(&fd->sc_dk, 0, 0);
   1141 
   1142 		/* Make sure seek really happened. */
   1143 		out_fdc(iot, ioh, NE7CMD_SENSEI);
   1144 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
   1145 		    cyl != bp->b_cylinder * fd->sc_type->step) {
   1146 #ifdef FD_DEBUG
   1147 			fdcstatus(&fd->sc_dev, 2, "seek failed");
   1148 #endif
   1149 			fdcretry(fdc);
   1150 			goto loop;
   1151 		}
   1152 		fd->sc_cylin = bp->b_cylinder;
   1153 		goto doio;
   1154 
   1155 	case IOTIMEDOUT:
   1156 		fiq_release(&fdc->sc_fh);
   1157 		IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
   1158 	case SEEKTIMEDOUT:
   1159 	case RECALTIMEDOUT:
   1160 	case RESETTIMEDOUT:
   1161 		fdcretry(fdc);
   1162 		goto loop;
   1163 
   1164 	case IOCOMPLETE: /* IO DONE, post-analyze */
   1165 		callout_stop(&fdc->sc_timo_ch);
   1166 
   1167 		disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
   1168 		    (bp->b_flags & B_READ));
   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, l)
   1327 	dev_t dev;
   1328 	u_long cmd;
   1329 	caddr_t addr;
   1330 	int flag;
   1331 	struct lwp *l;
   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, l);
   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, l)
   1509 	dev_t dev;
   1510 	struct ne7_fd_formb *finfo;
   1511 	struct lwp *l;
   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 = l->l_proc;
   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 %llx count %lx\n",
   1539 	    (unsigned long long)bp->b_blkno, bp->b_bcount);
   1540 #endif
   1541 
   1542 	/* now do the format */
   1543 	fdstrategy(bp);
   1544 
   1545 	/* ...and wait for it to complete */
   1546 	s = splbio();
   1547 	while(!(bp->b_flags & B_DONE)) {
   1548 		rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
   1549 		if (rv == EWOULDBLOCK)
   1550 			break;
   1551 	}
   1552 	splx(s);
   1553 
   1554 	if (rv == EWOULDBLOCK) {
   1555 		/* timed out */
   1556 		rv = EIO;
   1557 		biodone(bp);
   1558 	}
   1559 	if(bp->b_flags & B_ERROR) {
   1560 		rv = bp->b_error;
   1561 	}
   1562 	free(bp, M_TEMP);
   1563 	return rv;
   1564 }
   1565 
   1566 #include "md.h"
   1567 #if NMD > 0
   1568 
   1569 #include <dev/md.h>
   1570 
   1571 int load_memory_disc_from_floppy __P((struct md_conf *md, dev_t dev));
   1572 
   1573 int
   1574 load_memory_disc_from_floppy(md, dev)
   1575 	struct md_conf *md;
   1576 	dev_t dev;
   1577 {
   1578 	struct buf *bp;
   1579 	int loop;
   1580 	int s;
   1581 	int type;
   1582 	int floppysize;
   1583 
   1584 	if (bdevsw_lookup(dev) != &fd_bdevsw)
   1585 		return(EINVAL);
   1586 
   1587 	if (md->md_type == MD_UNCONFIGURED || md->md_addr == 0)
   1588 		return(EBUSY);
   1589 
   1590 	type = FDTYPE(dev) - 1;
   1591 	if (type < 0) type = 0;
   1592 	floppysize = fd_types[type].size << (fd_types[type].secsize + 7);
   1593 
   1594 	if (md->md_size < floppysize) {
   1595 		printf("Memory disc is not big enough for floppy image\n");
   1596 		return(EINVAL);
   1597 	}
   1598 
   1599 /* We have the memory disk ! */
   1600 
   1601 	printf("Loading memory disc : %4dK ", 0);
   1602 
   1603 /* obtain a buffer */
   1604 
   1605 	bp = geteblk(fd_types[type].sectrac * DEV_BSIZE);
   1606 
   1607 /* request no partition relocation by driver on I/O operations */
   1608 
   1609 	bp->b_dev = dev;
   1610 
   1611 	s = spl0();
   1612 
   1613 	if (fdopen(bp->b_dev, 0, 0, curlwp) != 0) {
   1614 		brelse(bp);
   1615 		printf("Cannot open floppy device\n");
   1616 			return(EINVAL);
   1617 	}
   1618 
   1619 	for (loop = 0;
   1620 	    loop < (floppysize / DEV_BSIZE / fd_types[type].sectrac);
   1621 	    ++loop) {
   1622 		printf("\x08\x08\x08\x08\x08\x08%4dK ",
   1623 		    loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
   1624 		bp->b_blkno = loop * fd_types[type].sectrac;
   1625 		bp->b_bcount = fd_types[type].sectrac * DEV_BSIZE;
   1626 		bp->b_flags |= B_READ;
   1627 		bp->b_error = 0;
   1628 		bp->b_resid = 0;
   1629 		fdstrategy(bp);
   1630 
   1631 		if (biowait(bp))
   1632 			panic("Cannot load floppy image");
   1633 
   1634 		memcpy((caddr_t)md->md_addr + loop * fd_types[type].sectrac
   1635 		    * DEV_BSIZE, (caddr_t)bp->b_data,
   1636 		    fd_types[type].sectrac * DEV_BSIZE);
   1637 	}
   1638 	printf("\x08\x08\x08\x08\x08\x08%4dK done\n",
   1639 	    loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
   1640 
   1641 	fdclose(bp->b_dev, 0, 0, curlwp);
   1642 
   1643 	brelse(bp);
   1644 
   1645 	splx(s);
   1646 	return(0);
   1647 }
   1648 
   1649 #endif
   1650