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