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