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