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