Home | History | Annotate | Line # | Download | only in dev
fd.c revision 1.93
      1 /*	$NetBSD: fd.c,v 1.93 2010/06/06 04:52:01 mrg 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 and Minoura Makoto.
      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  */
     65 
     66 #include <sys/cdefs.h>
     67 __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.93 2010/06/06 04:52:01 mrg Exp $");
     68 
     69 #include "rnd.h"
     70 #include "opt_ddb.h"
     71 #include "opt_m68k_arch.h"
     72 
     73 #include <sys/param.h>
     74 #include <sys/systm.h>
     75 #include <sys/callout.h>
     76 #include <sys/kernel.h>
     77 #include <sys/conf.h>
     78 #include <sys/file.h>
     79 #include <sys/stat.h>
     80 #include <sys/ioctl.h>
     81 #include <sys/malloc.h>
     82 #include <sys/device.h>
     83 #include <sys/disklabel.h>
     84 #include <sys/disk.h>
     85 #include <sys/buf.h>
     86 #include <sys/bufq.h>
     87 #include <sys/uio.h>
     88 #include <sys/syslog.h>
     89 #include <sys/queue.h>
     90 #include <sys/fdio.h>
     91 #if NRND > 0
     92 #include <sys/rnd.h>
     93 #endif
     94 
     95 #include <uvm/uvm_extern.h>
     96 
     97 #include <dev/cons.h>
     98 
     99 #include <machine/bus.h>
    100 #include <machine/cpu.h>
    101 
    102 #include <arch/x68k/dev/intiovar.h>
    103 #include <arch/x68k/dev/dmacvar.h>
    104 #include <arch/x68k/dev/fdreg.h>
    105 #include <arch/x68k/dev/opmvar.h> /* for CT1 access */
    106 
    107 #include "locators.h"
    108 
    109 #ifdef FDDEBUG
    110 #define DPRINTF(x)      if (fddebug) printf x
    111 int     fddebug = 0;
    112 #else
    113 #define DPRINTF(x)
    114 #endif
    115 
    116 #define FDUNIT(dev)	(minor(dev) / 8)
    117 #define FDTYPE(dev)	(minor(dev) % 8)
    118 
    119 enum fdc_state {
    120 	DEVIDLE = 0,
    121 	MOTORWAIT,
    122 	DOSEEK,
    123 	SEEKWAIT,
    124 	SEEKTIMEDOUT,
    125 	SEEKCOMPLETE,
    126 	DOIO,
    127 	IOCOMPLETE,
    128 	IOTIMEDOUT,
    129 	DORESET,
    130 	RESETCOMPLETE,
    131 	RESETTIMEDOUT,
    132 	DORECAL,
    133 	RECALWAIT,
    134 	RECALTIMEDOUT,
    135 	RECALCOMPLETE,
    136 	DOCOPY,
    137 	DOIOHALF,
    138 	COPYCOMPLETE,
    139 };
    140 
    141 /* software state, per controller */
    142 struct fdc_softc {
    143 	bus_space_tag_t sc_iot;		/* intio i/o space identifier */
    144 	bus_space_handle_t sc_ioh;	/* intio io handle */
    145 
    146 	struct callout sc_timo_ch;	/* timeout callout */
    147 	struct callout sc_intr_ch;	/* pseudo-intr callout */
    148 
    149 	bus_dma_tag_t sc_dmat;		/* intio DMA tag */
    150 	bus_dmamap_t sc_dmamap;		/* DMA map */
    151 	u_int8_t *sc_addr;			/* physical address */
    152 	struct dmac_channel_stat *sc_dmachan; /* intio DMA channel */
    153 	struct dmac_dma_xfer *sc_xfer;	/* DMA transfer */
    154 
    155 	struct fd_softc *sc_fd[4];	/* pointers to children */
    156 	TAILQ_HEAD(drivehead, fd_softc) sc_drives;
    157 	enum fdc_state sc_state;
    158 	int sc_errors;			/* number of retries so far */
    159 	u_char sc_status[7];		/* copy of registers */
    160 } fdc_softc;
    161 
    162 int fdcintr(void *);
    163 void fdcreset(struct fdc_softc *);
    164 
    165 /* controller driver configuration */
    166 int fdcprobe(device_t, cfdata_t, void *);
    167 void fdcattach(device_t, device_t, void *);
    168 int fdprint(void *, const char *);
    169 
    170 CFATTACH_DECL_NEW(fdc, sizeof(struct fdc_softc),
    171     fdcprobe, fdcattach, NULL, NULL);
    172 
    173 extern struct cfdriver fdc_cd;
    174 
    175 /*
    176  * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
    177  * we tell them apart.
    178  */
    179 struct fd_type {
    180 	int	sectrac;	/* sectors per track */
    181 	int	heads;		/* number of heads */
    182 	int	seccyl;		/* sectors per cylinder */
    183 	int	secsize;	/* size code for sectors */
    184 	int	datalen;	/* data len when secsize = 0 */
    185 	int	steprate;	/* step rate and head unload time */
    186 	int	gap1;		/* gap len between sectors */
    187 	int	gap2;		/* formatting gap */
    188 	int	cyls;		/* total num of cylinders */
    189 	int	size;		/* size of disk in sectors */
    190 	int	step;		/* steps per cylinder */
    191 	int	rate;		/* transfer speed code */
    192 	const char *name;
    193 };
    194 
    195 /* The order of entries in the following table is important -- BEWARE! */
    196 struct fd_type fd_types[] = {
    197         {  8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, "1.2MB/[1024bytes/sector]"    }, /* 1.2 MB japanese format */
    198         { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB"    }, /* 1.44MB diskette */
    199         { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB"    }, /* 1.2 MB AT-diskettes */
    200         {  9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */
    201         {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
    202         {  9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB"    }, /* 3.5" 720kB diskette */
    203         {  9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x"  }, /* 720kB in 1.2MB drive */
    204         {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x"  }, /* 360kB in 720kB drive */
    205 };
    206 
    207 /* software state, per disk (with up to 4 disks per ctlr) */
    208 struct fd_softc {
    209 	device_t sc_dev;
    210 	struct disk sc_dk;
    211 
    212 	struct fd_type *sc_deftype;	/* default type descriptor */
    213 	struct fd_type *sc_type;	/* current type descriptor */
    214 
    215 	struct callout sc_motoron_ch;
    216 	struct callout sc_motoroff_ch;
    217 
    218 	daddr_t	sc_blkno;	/* starting block number */
    219 	int sc_bcount;		/* byte count left */
    220 	int sc_opts;		/* user-set options */
    221 	int sc_skip;		/* bytes already transferred */
    222 	int sc_nblks;		/* number of blocks currently transferring */
    223 	int sc_nbytes;		/* number of bytes currently transferring */
    224 
    225 	int sc_drive;		/* physical unit number */
    226 	int sc_flags;
    227 #define	FD_BOPEN	0x01		/* it's open */
    228 #define	FD_COPEN	0x02		/* it's open */
    229 #define	FD_OPEN		(FD_BOPEN|FD_COPEN)	/* it's open */
    230 #define	FD_MOTOR	0x04		/* motor should be on */
    231 #define	FD_MOTOR_WAIT	0x08		/* motor coming up */
    232 #define	FD_ALIVE	0x10		/* alive */
    233 	int sc_cylin;		/* where we think the head is */
    234 
    235 	TAILQ_ENTRY(fd_softc) sc_drivechain;
    236 	int sc_ops;		/* I/O ops since last switch */
    237 	struct bufq_state *sc_q;/* pending I/O requests */
    238 	int sc_active;		/* number of active I/O operations */
    239 	u_char *sc_copybuf;	/* for secsize >=3 */
    240 	u_char sc_part;		/* for secsize >=3 */
    241 #define	SEC_P10	0x02		/* first part */
    242 #define	SEC_P01	0x01		/* second part */
    243 #define	SEC_P11	0x03		/* both part */
    244 
    245 #if NRND > 0
    246 	rndsource_element_t	rnd_source;
    247 #endif
    248 };
    249 
    250 /* floppy driver configuration */
    251 int fdprobe(device_t, cfdata_t, void *);
    252 void fdattach(device_t, device_t, void *);
    253 
    254 CFATTACH_DECL_NEW(fd, sizeof(struct fd_softc),
    255     fdprobe, fdattach, NULL, NULL);
    256 
    257 extern struct cfdriver fd_cd;
    258 
    259 dev_type_open(fdopen);
    260 dev_type_close(fdclose);
    261 dev_type_read(fdread);
    262 dev_type_write(fdwrite);
    263 dev_type_ioctl(fdioctl);
    264 dev_type_strategy(fdstrategy);
    265 
    266 const struct bdevsw fd_bdevsw = {
    267 	fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK
    268 };
    269 
    270 const struct cdevsw fd_cdevsw = {
    271 	fdopen, fdclose, fdread, fdwrite, fdioctl,
    272 	nostop, notty, nopoll, nommap, nokqfilter, D_DISK
    273 };
    274 
    275 void fdstart(struct fd_softc *);
    276 
    277 struct dkdriver fddkdriver = { fdstrategy };
    278 
    279 void fd_set_motor(struct fdc_softc *, int);
    280 void fd_motor_off(void *);
    281 void fd_motor_on(void *);
    282 int fdcresult(struct fdc_softc *);
    283 int out_fdc(bus_space_tag_t, bus_space_handle_t, u_char);
    284 void fdcstart(struct fdc_softc *);
    285 void fdcstatus(device_t, int, const char *);
    286 void fdctimeout(void *);
    287 void fdcpseudointr(void *);
    288 void fdcretry(struct fdc_softc *);
    289 void fdfinish(struct fd_softc *, struct buf *);
    290 inline struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t);
    291 static int fdcpoll(struct fdc_softc *);
    292 static int fdgetdisklabel(struct fd_softc *, dev_t);
    293 static void fd_do_eject(struct fdc_softc *, int);
    294 
    295 void fd_mountroot_hook(device_t);
    296 
    297 /* DMA transfer routines */
    298 inline static void fdc_dmastart(struct fdc_softc *, int, void *, vsize_t);
    299 static int fdcdmaintr(void *);
    300 static int fdcdmaerrintr(void *);
    301 
    302 inline static void
    303 fdc_dmastart(struct fdc_softc *fdc, int read, void *addr, vsize_t count)
    304 {
    305 	int error;
    306 
    307 	DPRINTF(("fdc_dmastart: %s, addr = %p, count = %ld\n",
    308 		 read ? "read" : "write", (void *) addr, count));
    309 
    310 	error = bus_dmamap_load(fdc->sc_dmat, fdc->sc_dmamap, addr, count,
    311 				0, BUS_DMA_NOWAIT);
    312 	if (error) {
    313 		panic ("fdc_dmastart: cannot load dmamap");
    314 	}
    315 
    316 	bus_dmamap_sync(fdc->sc_dmat, fdc->sc_dmamap, 0, count,
    317 			read?BUS_DMASYNC_PREREAD:BUS_DMASYNC_PREWRITE);
    318 
    319 	fdc->sc_xfer = dmac_prepare_xfer(fdc->sc_dmachan, fdc->sc_dmat,
    320 					 fdc->sc_dmamap,
    321 					 (read?
    322 					  DMAC_OCR_DIR_DTM:DMAC_OCR_DIR_MTD),
    323 					 (DMAC_SCR_MAC_COUNT_UP|
    324 					  DMAC_SCR_DAC_NO_COUNT),
    325 					 (u_int8_t*) (fdc->sc_addr +
    326 						      fddata));	/* XXX */
    327 
    328 	dmac_start_xfer(fdc->sc_dmachan->ch_softc, fdc->sc_xfer);
    329 }
    330 
    331 static int
    332 fdcdmaintr(void *arg)
    333 {
    334 	struct fdc_softc *fdc = arg;
    335 
    336 	bus_dmamap_unload(fdc->sc_dmat, fdc->sc_dmamap);
    337 
    338 	return 0;
    339 }
    340 
    341 static int
    342 fdcdmaerrintr(void *dummy)
    343 {
    344 	DPRINTF(("fdcdmaerrintr\n"));
    345 
    346 	return 0;
    347 }
    348 
    349 /* ARGSUSED */
    350 int
    351 fdcprobe(device_t parent, cfdata_t cf, void *aux)
    352 {
    353 	struct intio_attach_args *ia = aux;
    354 
    355 	if (strcmp(ia->ia_name, "fdc") != 0)
    356 		return 0;
    357 
    358 	if (ia->ia_addr == INTIOCF_ADDR_DEFAULT)
    359 		ia->ia_addr = FDC_ADDR;
    360 	if (ia->ia_intr == INTIOCF_INTR_DEFAULT)
    361 		ia->ia_intr = FDC_INTR;
    362 	if (ia->ia_dma == INTIOCF_DMA_DEFAULT)
    363 		ia->ia_dma = FDC_DMA;
    364 	if (ia->ia_dmaintr == INTIOCF_DMAINTR_DEFAULT)
    365 		ia->ia_dmaintr = FDC_DMAINTR;
    366 
    367 	if ((ia->ia_intr & 0x03) != 0)
    368 		return 0;
    369 
    370 	ia->ia_size = 0x2000;
    371 	if (intio_map_allocate_region (parent, ia, INTIO_MAP_TESTONLY))
    372 		return 0;
    373 
    374 	/* builtin device; always there */
    375 	return 1;
    376 }
    377 
    378 /*
    379  * Arguments passed between fdcattach and fdprobe.
    380  */
    381 struct fdc_attach_args {
    382 	int fa_drive;
    383 	struct fd_type *fa_deftype;
    384 };
    385 
    386 /*
    387  * Print the location of a disk drive (called just before attaching the
    388  * the drive).  If `fdc' is not NULL, the drive was found but was not
    389  * in the system config file; print the drive name as well.
    390  * Return QUIET (config_find ignores this if the device was configured) to
    391  * avoid printing `fdN not configured' messages.
    392  */
    393 int
    394 fdprint(void *aux, const char *fdc)
    395 {
    396 	struct fdc_attach_args *fa = aux;
    397 
    398 	if (!fdc)
    399 		aprint_normal(" drive %d", fa->fa_drive);
    400 	return QUIET;
    401 }
    402 
    403 void
    404 fdcattach(device_t parent, device_t self, void *aux)
    405 {
    406 	struct fdc_softc *fdc = device_private(self);
    407 	bus_space_tag_t iot;
    408 	bus_space_handle_t ioh;
    409 	struct intio_attach_args *ia = aux;
    410 	struct fdc_attach_args fa;
    411 
    412 	iot = ia->ia_bst;
    413 
    414 	aprint_normal("\n");
    415 
    416 	callout_init(&fdc->sc_timo_ch, 0);
    417 	callout_init(&fdc->sc_intr_ch, 0);
    418 
    419 	/* Re-map the I/O space. */
    420 	bus_space_map(iot, ia->ia_addr, 0x2000, BUS_SPACE_MAP_SHIFTED, &ioh);
    421 
    422 	fdc->sc_iot = iot;
    423 	fdc->sc_ioh = ioh;
    424 	fdc->sc_addr = (void *)ia->ia_addr;
    425 
    426 	fdc->sc_dmat = ia->ia_dmat;
    427 	fdc->sc_state = DEVIDLE;
    428 	TAILQ_INIT(&fdc->sc_drives);
    429 
    430 	/* Initialize DMAC channel */
    431 	fdc->sc_dmachan = dmac_alloc_channel(parent, ia->ia_dma, "fdc",
    432 					     ia->ia_dmaintr, fdcdmaintr, fdc,
    433 					     ia->ia_dmaintr+1, fdcdmaerrintr,
    434 					     fdc);
    435 	if (bus_dmamap_create(fdc->sc_dmat, FDC_MAXIOSIZE, 1, DMAC_MAXSEGSZ,
    436 			      0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
    437 			      &fdc->sc_dmamap)) {
    438 		aprint_error_dev(self, "can't set up intio DMA map\n");
    439 		return;
    440 	}
    441 
    442 	if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc))
    443 		panic ("Could not establish interrupt (duplicated vector?).");
    444 	intio_set_ivec(ia->ia_intr);
    445 
    446 	/* reset */
    447 	intio_disable_intr(SICILIAN_INTR_FDD);
    448 	intio_enable_intr(SICILIAN_INTR_FDC);
    449 	fdcresult(fdc);
    450 	fdcreset(fdc);
    451 
    452 	aprint_normal_dev(self, "uPD72065 FDC\n");
    453 	out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
    454 	out_fdc(iot, ioh, 0xd0);
    455 	out_fdc(iot, ioh, 0x10);
    456 
    457 	/* physical limit: four drives per controller. */
    458 	for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
    459 		(void)config_found(self, (void *)&fa, fdprint);
    460 	}
    461 
    462 	intio_enable_intr(SICILIAN_INTR_FDC);
    463 }
    464 
    465 void
    466 fdcreset(struct fdc_softc *fdc)
    467 {
    468 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdsts, NE7CMD_RESET);
    469 }
    470 
    471 static int
    472 fdcpoll(struct fdc_softc *fdc)
    473 {
    474 	int i = 25000, n;
    475 	while (--i > 0) {
    476 		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
    477 			out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
    478 			n = fdcresult(fdc);
    479 			break;
    480 		}
    481 		DELAY(100);
    482 	}
    483 	return i;
    484 }
    485 
    486 int
    487 fdprobe(device_t parent, cfdata_t cf, void *aux)
    488 {
    489 	struct fdc_softc *fdc = device_private(parent);
    490 	struct fd_type *type;
    491 	struct fdc_attach_args *fa = aux;
    492 	int drive = fa->fa_drive;
    493 	bus_space_tag_t iot = fdc->sc_iot;
    494 	bus_space_handle_t ioh = fdc->sc_ioh;
    495 	int n = 0;
    496 	int found = 0;
    497 	int i;
    498 
    499 	if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
    500 	    cf->cf_loc[FDCCF_UNIT] != drive)
    501 		return 0;
    502 
    503 	type = &fd_types[0];	/* XXX 1.2MB */
    504 
    505 	intio_disable_intr(SICILIAN_INTR_FDC);
    506 
    507 	/* select drive and turn on motor */
    508 	bus_space_write_1(iot, ioh, fdctl, 0x80 | (type->rate << 4)| drive);
    509 	fdc_force_ready(FDCRDY);
    510 	fdcpoll(fdc);
    511 
    512 retry:
    513 	out_fdc(iot, ioh, NE7CMD_RECAL);
    514 	out_fdc(iot, ioh, drive);
    515 
    516 	i = 25000;
    517 	while (--i > 0) {
    518 		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
    519 			out_fdc(iot, ioh, NE7CMD_SENSEI);
    520 			n = fdcresult(fdc);
    521 			break;
    522 		}
    523 		DELAY(100);
    524 	}
    525 
    526 #ifdef FDDEBUG
    527 	{
    528 		int _i;
    529 		DPRINTF(("fdprobe: status"));
    530 		for (_i = 0; _i < n; _i++)
    531 			DPRINTF((" %x", fdc->sc_status[_i]));
    532 		DPRINTF(("\n"));
    533 	}
    534 #endif
    535 
    536 	if (n == 2) {
    537 		if ((fdc->sc_status[0] & 0xf0) == 0x20)
    538 			found = 1;
    539 		else if ((fdc->sc_status[0] & 0xf0) == 0xc0)
    540 			goto retry;
    541 	}
    542 
    543 	/* turn off motor */
    544 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh,
    545 			  fdctl, (type->rate << 4)| drive);
    546 	fdc_force_ready(FDCSTBY);
    547 	if (!found) {
    548 		intio_enable_intr(SICILIAN_INTR_FDC);
    549 		return 0;
    550 	}
    551 
    552 	return 1;
    553 }
    554 
    555 /*
    556  * Controller is working, and drive responded.  Attach it.
    557  */
    558 void
    559 fdattach(device_t parent, device_t self, void *aux)
    560 {
    561 	struct fdc_softc *fdc = device_private(parent);
    562 	struct fd_softc *fd = device_private(self);
    563 	struct fdc_attach_args *fa = aux;
    564 	struct fd_type *type = &fd_types[0];	/* XXX 1.2MB */
    565 	int drive = fa->fa_drive;
    566 
    567 	callout_init(&fd->sc_motoron_ch, 0);
    568 	callout_init(&fd->sc_motoroff_ch, 0);
    569 
    570 	fd->sc_dev = self;
    571 	fd->sc_flags = 0;
    572 
    573 	if (type)
    574 		aprint_normal(": %s, %d cyl, %d head, %d sec\n", type->name,
    575 		       type->cyls, type->heads, type->sectrac);
    576 	else
    577 		aprint_normal(": density unknown\n");
    578 
    579 	bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER);
    580 	fd->sc_cylin = -1;
    581 	fd->sc_drive = drive;
    582 	fd->sc_deftype = type;
    583 	fdc->sc_fd[drive] = fd;
    584 
    585 	fd->sc_copybuf = (u_char *)malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK);
    586 	if (fd->sc_copybuf == 0)
    587 		aprint_error("%s: WARNING!! malloc() failed.\n", __func__);
    588 	fd->sc_flags |= FD_ALIVE;
    589 
    590 	/*
    591 	 * Initialize and attach the disk structure.
    592 	 */
    593 	disk_init(&fd->sc_dk, device_xname(fd->sc_dev), &fddkdriver);
    594 	disk_attach(&fd->sc_dk);
    595 
    596 	/*
    597 	 * Establish a mountroot_hook anyway in case we booted
    598 	 * with RB_ASKNAME and get selected as the boot device.
    599 	 */
    600 	mountroothook_establish(fd_mountroot_hook, fd->sc_dev);
    601 
    602 #if NRND > 0
    603 	rnd_attach_source(&fd->rnd_source, device_xname(fd->sc_dev),
    604 			  RND_TYPE_DISK, 0);
    605 #endif
    606 }
    607 
    608 inline struct fd_type *
    609 fd_dev_to_type(struct fd_softc *fd, dev_t dev)
    610 {
    611 	int type = FDTYPE(dev);
    612 
    613 	if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
    614 		return NULL;
    615 	return &fd_types[type];
    616 }
    617 
    618 void
    619 fdstrategy(struct buf *bp)
    620 {
    621 	struct fd_softc *fd;
    622 	int unit;
    623 	int sz;
    624 	int s;
    625 
    626 	unit = FDUNIT(bp->b_dev);
    627 	fd = device_lookup_private(&fd_cd, unit);
    628 	if (fd == NULL) {
    629 		bp->b_error = EINVAL;
    630 		goto done;
    631 	}
    632 
    633 	if (bp->b_blkno < 0 ||
    634 	    (bp->b_bcount % FDC_BSIZE) != 0) {
    635 		DPRINTF(("fdstrategy: unit=%d, blkno=%" PRId64 ", "
    636 			 "bcount=%d\n", unit,
    637 			 bp->b_blkno, bp->b_bcount));
    638 		bp->b_error = EINVAL;
    639 		goto done;
    640 	}
    641 
    642 	/* If it's a null transfer, return immediately. */
    643 	if (bp->b_bcount == 0)
    644 		goto done;
    645 
    646 	sz = howmany(bp->b_bcount, FDC_BSIZE);
    647 
    648 	if (bp->b_blkno + sz >
    649 	    (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
    650 		sz = (fd->sc_type->size << (fd->sc_type->secsize - 2))
    651 		     - bp->b_blkno;
    652 		if (sz == 0) {
    653 			/* If exactly at end of disk, return EOF. */
    654 			bp->b_resid = bp->b_bcount;
    655 			goto done;
    656 		}
    657 		if (sz < 0) {
    658 			/* If past end of disk, return EINVAL. */
    659 			bp->b_error = EINVAL;
    660 			goto done;
    661 		}
    662 		/* Otherwise, truncate request. */
    663 		bp->b_bcount = sz << DEV_BSHIFT;
    664 	}
    665 
    666 	bp->b_rawblkno = bp->b_blkno;
    667 	bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)
    668 		/ (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2)));
    669 
    670 	DPRINTF(("fdstrategy: %s b_blkno %" PRId64 " b_bcount %d cylin %d\n",
    671 		 bp->b_flags & B_READ ? "read" : "write",
    672 		 bp->b_blkno, bp->b_bcount, bp->b_cylinder));
    673 	/* Queue transfer on drive, activate drive and controller if idle. */
    674 	s = splbio();
    675 	bufq_put(fd->sc_q, bp);
    676 	callout_stop(&fd->sc_motoroff_ch);		/* a good idea */
    677 	if (fd->sc_active == 0)
    678 		fdstart(fd);
    679 #ifdef DIAGNOSTIC
    680 	else {
    681 		struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
    682 		if (fdc->sc_state == DEVIDLE) {
    683 			printf("fdstrategy: controller inactive\n");
    684 			fdcstart(fdc);
    685 		}
    686 	}
    687 #endif
    688 	splx(s);
    689 	return;
    690 
    691 done:
    692 	/* Toss transfer; we're done early. */
    693 	biodone(bp);
    694 }
    695 
    696 void
    697 fdstart(struct fd_softc *fd)
    698 {
    699 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
    700 	int active = !TAILQ_EMPTY(&fdc->sc_drives);
    701 
    702 	/* Link into controller queue. */
    703 	fd->sc_active = 1;
    704 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    705 
    706 	/* If controller not already active, start it. */
    707 	if (!active)
    708 		fdcstart(fdc);
    709 }
    710 
    711 void
    712 fdfinish(struct fd_softc *fd, struct buf *bp)
    713 {
    714 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
    715 
    716 	/*
    717 	 * Move this drive to the end of the queue to give others a `fair'
    718 	 * chance.  We only force a switch if N operations are completed while
    719 	 * another drive is waiting to be serviced, since there is a long motor
    720 	 * startup delay whenever we switch.
    721 	 */
    722 	(void)bufq_get(fd->sc_q);
    723 	if (TAILQ_NEXT(fd, sc_drivechain) && ++fd->sc_ops >= 8) {
    724 		fd->sc_ops = 0;
    725 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
    726 		if (bufq_peek(fd->sc_q) != NULL) {
    727 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    728 		} else
    729 			fd->sc_active = 0;
    730 	}
    731 	bp->b_resid = fd->sc_bcount;
    732 	fd->sc_skip = 0;
    733 
    734 #if NRND > 0
    735 	rnd_add_uint32(&fd->rnd_source, bp->b_blkno);
    736 #endif
    737 
    738 	biodone(bp);
    739 	/* turn off motor 5s from now */
    740 	callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
    741 	fdc->sc_state = DEVIDLE;
    742 }
    743 
    744 int
    745 fdread(dev_t dev, struct uio *uio, int flags)
    746 {
    747 
    748 	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
    749 }
    750 
    751 int
    752 fdwrite(dev_t dev, struct uio *uio, int flags)
    753 {
    754 
    755 	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
    756 }
    757 
    758 void
    759 fd_set_motor(struct fdc_softc *fdc, int reset)
    760 {
    761 	struct fd_softc *fd;
    762 	int n;
    763 
    764 	DPRINTF(("fd_set_motor:\n"));
    765 	for (n = 0; n < 4; n++)
    766 		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) {
    767 			bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl,
    768 					  0x80 | (fd->sc_type->rate << 4)| n);
    769 		}
    770 }
    771 
    772 void
    773 fd_motor_off(void *arg)
    774 {
    775 	struct fd_softc *fd = arg;
    776  	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
    777 	int s;
    778 
    779 	DPRINTF(("fd_motor_off:\n"));
    780 
    781 	s = splbio();
    782 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
    783 	bus_space_write_1 (fdc->sc_iot, fdc->sc_ioh, fdctl,
    784 			   (fd->sc_type->rate << 4) | fd->sc_drive);
    785 #if 0
    786 	fd_set_motor(fdc, 0); /* XXX */
    787 #endif
    788 	splx(s);
    789 }
    790 
    791 void
    792 fd_motor_on(void *arg)
    793 {
    794 	struct fd_softc *fd = arg;
    795 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
    796 	int s;
    797 
    798 	DPRINTF(("fd_motor_on:\n"));
    799 
    800 	s = splbio();
    801 	fd->sc_flags &= ~FD_MOTOR_WAIT;
    802 	if ((TAILQ_FIRST(&fdc->sc_drives) == fd) && (fdc->sc_state == MOTORWAIT))
    803 		(void) fdcintr(fdc);
    804 	splx(s);
    805 }
    806 
    807 int
    808 fdcresult(struct fdc_softc *fdc)
    809 {
    810 	bus_space_tag_t iot = fdc->sc_iot;
    811 	bus_space_handle_t ioh = fdc->sc_ioh;
    812 	u_char i;
    813 	int j = 100000,
    814 	    n = 0;
    815 
    816 	for (; j; j--) {
    817 		i = bus_space_read_1(iot, ioh, fdsts) &
    818 		  (NE7_DIO | NE7_RQM | NE7_CB);
    819 
    820 		if (i == NE7_RQM)
    821 			return n;
    822 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
    823 			if (n >= sizeof(fdc->sc_status)) {
    824 				log(LOG_ERR, "fdcresult: overrun\n");
    825 				return -1;
    826 			}
    827 			fdc->sc_status[n++] =
    828 			  bus_space_read_1(iot, ioh, fddata);
    829 		}
    830 		delay(10);
    831 	}
    832 	log(LOG_ERR, "fdcresult: timeout\n");
    833 	return -1;
    834 }
    835 
    836 int
    837 out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x)
    838 {
    839 	int i = 100000;
    840 
    841 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
    842 	if (i <= 0)
    843 		return -1;
    844 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
    845 	if (i <= 0)
    846 		return -1;
    847 	bus_space_write_1(iot, ioh, fddata, x);
    848 	return 0;
    849 }
    850 
    851 int
    852 fdopen(dev_t dev, int flags, int mode, struct lwp *l)
    853 {
    854 	int unit;
    855 	struct fd_softc *fd;
    856 	struct fd_type *type;
    857 	struct fdc_softc *fdc;
    858 
    859 	unit = FDUNIT(dev);
    860 	fd = device_lookup_private(&fd_cd, unit);
    861 	if (fd == NULL)
    862 		return ENXIO;
    863 	type = fd_dev_to_type(fd, dev);
    864 	if (type == NULL)
    865 		return ENXIO;
    866 
    867 	if ((fd->sc_flags & FD_OPEN) != 0 &&
    868 	    fd->sc_type != type)
    869 		return EBUSY;
    870 
    871 	fdc = device_private(device_parent(fd->sc_dev));
    872 	if ((fd->sc_flags & FD_OPEN) == 0) {
    873 		/* Lock eject button */
    874 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
    875 				  0x40 | ( 1 << unit));
    876 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x40);
    877 	}
    878 
    879 	fd->sc_type = type;
    880 	fd->sc_cylin = -1;
    881 
    882 	switch (mode) {
    883 	case S_IFCHR:
    884 		fd->sc_flags |= FD_COPEN;
    885 		break;
    886 	case S_IFBLK:
    887 		fd->sc_flags |= FD_BOPEN;
    888 		break;
    889 	}
    890 
    891 	fdgetdisklabel(fd, dev);
    892 
    893 	return 0;
    894 }
    895 
    896 int
    897 fdclose(dev_t dev, int flags, int mode, struct lwp *l)
    898 {
    899 	int unit = FDUNIT(dev);
    900 	struct fd_softc *fd = device_lookup_private(&fd_cd, unit);
    901 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
    902 
    903 	DPRINTF(("fdclose %d\n", unit));
    904 
    905 	switch (mode) {
    906 	case S_IFCHR:
    907 		fd->sc_flags &= ~FD_COPEN;
    908 		break;
    909 	case S_IFBLK:
    910 		fd->sc_flags &= ~FD_BOPEN;
    911 		break;
    912 	}
    913 
    914 	if ((fd->sc_flags & FD_OPEN) == 0) {
    915 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
    916 				  ( 1 << unit));
    917 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0);
    918 	}
    919 	return 0;
    920 }
    921 
    922 void
    923 fdcstart(struct fdc_softc *fdc)
    924 {
    925 
    926 #ifdef DIAGNOSTIC
    927 	/* only got here if controller's drive queue was inactive; should
    928 	   be in idle state */
    929 	if (fdc->sc_state != DEVIDLE) {
    930 		printf("fdcstart: not idle\n");
    931 		return;
    932 	}
    933 #endif
    934 	(void) fdcintr(fdc);
    935 }
    936 
    937 
    938 static void
    939 fdcpstatus(int n, struct fdc_softc *fdc)
    940 {
    941 	char bits[64];
    942 
    943 	switch (n) {
    944 	case 0:
    945 		printf("\n");
    946 		break;
    947 	case 2:
    948 		snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]);
    949 		printf(" (st0 %s cyl %d)\n", bits, fdc->sc_status[1]);
    950 		break;
    951 	case 7:
    952 		snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]);
    953 		printf(" (st0 %s", bits);
    954 		snprintb(bits, sizeof(bits), NE7_ST1BITS, fdc->sc_status[1]);
    955 		printf(" st1 %s", bits);
    956 		snprintb(bits, sizeof(bits), NE7_ST2BITS, fdc->sc_status[2]);
    957 		printf(" st2 %s", bits);
    958 		printf(" cyl %d head %d sec %d)\n",
    959 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
    960 		break;
    961 #ifdef DIAGNOSTIC
    962 	default:
    963 		printf("\nfdcstatus: weird size");
    964 		break;
    965 #endif
    966 	}
    967 }
    968 
    969 void
    970 fdcstatus(device_t dv, int n, const char *s)
    971 {
    972 	struct fdc_softc *fdc = device_private(device_parent(dv));
    973 
    974 	if (n == 0) {
    975 		out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
    976 		(void) fdcresult(fdc);
    977 		n = 2;
    978 	}
    979 
    980 	printf("%s: %s: state %d", device_xname(dv), s, fdc->sc_state);
    981 	fdcpstatus(n, fdc);
    982 }
    983 
    984 void
    985 fdctimeout(void *arg)
    986 {
    987 	struct fdc_softc *fdc = arg;
    988 	struct fd_softc *fd = TAILQ_FIRST(&fdc->sc_drives);
    989 	int s;
    990 
    991 	s = splbio();
    992 	fdcstatus(fd->sc_dev, 0, "timeout");
    993 
    994 	if (bufq_peek(fd->sc_q) != NULL)
    995 		fdc->sc_state++;
    996 	else
    997 		fdc->sc_state = DEVIDLE;
    998 
    999 	(void) fdcintr(fdc);
   1000 	splx(s);
   1001 }
   1002 
   1003 #if 0
   1004 void
   1005 fdcpseudointr(void *arg)
   1006 {
   1007 	int s;
   1008 	struct fdc_softc *fdc = arg;
   1009 
   1010 	/* just ensure it has the right spl */
   1011 	s = splbio();
   1012 	(void) fdcintr(fdc);
   1013 	splx(s);
   1014 }
   1015 #endif
   1016 
   1017 int
   1018 fdcintr(void *arg)
   1019 {
   1020 	struct fdc_softc *fdc = arg;
   1021 #define	st0	fdc->sc_status[0]
   1022 #define	cyl	fdc->sc_status[1]
   1023 	struct fd_softc *fd;
   1024 	struct buf *bp;
   1025 	bus_space_tag_t iot = fdc->sc_iot;
   1026 	bus_space_handle_t ioh = fdc->sc_ioh;
   1027 	int read, head, sec, pos, i, sectrac, nblks;
   1028 	int	tmp;
   1029 	struct fd_type *type;
   1030 
   1031 loop:
   1032 	fd = TAILQ_FIRST(&fdc->sc_drives);
   1033 	if (fd == NULL) {
   1034 		DPRINTF(("fdcintr: set DEVIDLE\n"));
   1035 		if (fdc->sc_state == DEVIDLE) {
   1036 			if (intio_get_sicilian_intr() & SICILIAN_STAT_FDC) {
   1037 				out_fdc(iot, ioh, NE7CMD_SENSEI);
   1038 				if ((tmp = fdcresult(fdc)) != 2 ||
   1039 				    (st0 & 0xf8) != 0x20) {
   1040 					goto loop;
   1041 				}
   1042 			}
   1043 		}
   1044 		/* no drives waiting; end */
   1045 		fdc->sc_state = DEVIDLE;
   1046 		return 1;
   1047 	}
   1048 
   1049 	/* Is there a transfer to this drive?  If not, deactivate drive. */
   1050 	bp = bufq_peek(fd->sc_q);
   1051 	if (bp == NULL) {
   1052 		fd->sc_ops = 0;
   1053 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
   1054 		fd->sc_active = 0;
   1055 		goto loop;
   1056 	}
   1057 
   1058 	switch (fdc->sc_state) {
   1059 	case DEVIDLE:
   1060 		DPRINTF(("fdcintr: in DEVIDLE\n"));
   1061 		fdc->sc_errors = 0;
   1062 		fd->sc_skip = 0;
   1063 		fd->sc_bcount = bp->b_bcount;
   1064 		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
   1065 		callout_stop(&fd->sc_motoroff_ch);
   1066 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
   1067 			fdc->sc_state = MOTORWAIT;
   1068 			return 1;
   1069 		}
   1070 		if ((fd->sc_flags & FD_MOTOR) == 0) {
   1071 			/* Turn on the motor */
   1072 			/* being careful about other drives. */
   1073 			for (i = 0; i < 4; i++) {
   1074 				struct fd_softc *ofd = fdc->sc_fd[i];
   1075 				if (ofd && ofd->sc_flags & FD_MOTOR) {
   1076 					callout_stop(&ofd->sc_motoroff_ch);
   1077 					ofd->sc_flags &=
   1078 						~(FD_MOTOR | FD_MOTOR_WAIT);
   1079 					break;
   1080 				}
   1081 			}
   1082 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
   1083 			fd_set_motor(fdc, 0);
   1084 			fdc->sc_state = MOTORWAIT;
   1085 			/* allow .5s for motor to stabilize */
   1086 			callout_reset(&fd->sc_motoron_ch, hz / 2,
   1087 			    fd_motor_on, fd);
   1088 			return 1;
   1089 		}
   1090 		/* Make sure the right drive is selected. */
   1091 		fd_set_motor(fdc, 0);
   1092 
   1093 		/* fall through */
   1094 	case DOSEEK:
   1095 	doseek:
   1096 		DPRINTF(("fdcintr: in DOSEEK\n"));
   1097 		if (fd->sc_cylin == bp->b_cylinder)
   1098 			goto doio;
   1099 
   1100 		out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
   1101 		out_fdc(iot, ioh, 0xd0);	/* XXX const */
   1102 		out_fdc(iot, ioh, 0x10);
   1103 
   1104 		out_fdc(iot, ioh, NE7CMD_SEEK);	/* seek function */
   1105 		out_fdc(iot, ioh, fd->sc_drive);	/* drive number */
   1106 		out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
   1107 
   1108 		fd->sc_cylin = -1;
   1109 		fdc->sc_state = SEEKWAIT;
   1110 
   1111 		iostat_seek(fd->sc_dk.dk_stats);
   1112 		disk_busy(&fd->sc_dk);
   1113 
   1114 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
   1115 		return 1;
   1116 
   1117 	case DOIO:
   1118 	doio:
   1119 		DPRINTF(("fdcintr: DOIO: "));
   1120 		type = fd->sc_type;
   1121 		sectrac = type->sectrac;
   1122 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
   1123 		sec = pos / (1 << (type->secsize - 2));
   1124 		if (type->secsize == 2) {
   1125 			fd->sc_part = SEC_P11;
   1126 			nblks = (sectrac - sec) << (type->secsize - 2);
   1127 			nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
   1128 			DPRINTF(("nblks(0)"));
   1129 		} else if ((fd->sc_blkno % 2) == 0) {
   1130 			if (fd->sc_bcount & 0x00000200) {
   1131 				if (fd->sc_bcount == FDC_BSIZE) {
   1132 					fd->sc_part = SEC_P10;
   1133 					nblks = 1;
   1134 					DPRINTF(("nblks(1)"));
   1135 				} else {
   1136 					fd->sc_part = SEC_P11;
   1137 					nblks = (sectrac - sec) * 2;
   1138 					nblks = min(nblks, fd->sc_bcount
   1139 						    / FDC_BSIZE - 1);
   1140 					DPRINTF(("nblks(2)"));
   1141 				}
   1142 			} else {
   1143 				fd->sc_part = SEC_P11;
   1144 				nblks = (sectrac - sec)
   1145 					<< (type->secsize - 2);
   1146 				nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
   1147 				DPRINTF(("nblks(3)"));
   1148 			}
   1149 		} else {
   1150 			fd->sc_part = SEC_P01;
   1151 			nblks = 1;
   1152 			DPRINTF(("nblks(4)"));
   1153 		}
   1154 		nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
   1155 		DPRINTF((" %d\n", nblks));
   1156 		fd->sc_nblks = nblks;
   1157 		fd->sc_nbytes = nblks * FDC_BSIZE;
   1158 		head = (fd->sc_blkno
   1159 			% (type->seccyl * (1 << (type->secsize - 2))))
   1160 			 / (type->sectrac * (1 << (type->secsize - 2)));
   1161 
   1162 #ifdef DIAGNOSTIC
   1163 		{int block;
   1164 		 block = ((fd->sc_cylin * type->heads + head) * type->sectrac
   1165 			  + sec) * (1 << (type->secsize - 2));
   1166 		 block += (fd->sc_part == SEC_P01) ? 1 : 0;
   1167 		 if (block != fd->sc_blkno) {
   1168 			 printf("C H R N: %d %d %d %d\n",
   1169 				fd->sc_cylin, head, sec, type->secsize);
   1170 			 printf("fdcintr: doio: block %d != blkno %" PRId64 "\n",
   1171 				block, fd->sc_blkno);
   1172 #ifdef DDB
   1173 			 Debugger();
   1174 #endif
   1175 		 }
   1176 		}
   1177 #endif
   1178 		read = bp->b_flags & B_READ;
   1179 		DPRINTF(("fdcintr: %s drive %d track %d "
   1180 		         "head %d sec %d nblks %d, skip %d\n",
   1181 			 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
   1182 			 head, sec, nblks, fd->sc_skip));
   1183 		DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
   1184 			 type->secsize));
   1185 
   1186 		if (fd->sc_part != SEC_P11)
   1187 			goto docopy;
   1188 
   1189 		fdc_dmastart(fdc, read, (char *)bp->b_data + fd->sc_skip,
   1190 			     fd->sc_nbytes);
   1191 		if (read)
   1192 			out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
   1193 		else
   1194 			out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
   1195 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1196 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
   1197 		out_fdc(iot, ioh, head);
   1198 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
   1199 		out_fdc(iot, ioh, type->secsize);	/* sector size */
   1200 		out_fdc(iot, ioh, type->sectrac);	/* sectors/track */
   1201 		out_fdc(iot, ioh, type->gap1);		/* gap1 size */
   1202 		out_fdc(iot, ioh, type->datalen);	/* data length */
   1203 		fdc->sc_state = IOCOMPLETE;
   1204 
   1205 		disk_busy(&fd->sc_dk);
   1206 
   1207 		/* allow 2 seconds for operation */
   1208 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1209 		return 1;				/* will return later */
   1210 
   1211 	case DOCOPY:
   1212 	docopy:
   1213 		DPRINTF(("fdcintr: DOCOPY:\n"));
   1214 		type = fd->sc_type;
   1215 		head = (fd->sc_blkno
   1216 			% (type->seccyl * (1 << (type->secsize - 2))))
   1217 			 / (type->sectrac * (1 << (type->secsize - 2)));
   1218 		pos = fd->sc_blkno % (type->sectrac * (1 << (type->secsize - 2)));
   1219 		sec = pos / (1 << (type->secsize - 2));
   1220 		fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024);
   1221 		out_fdc(iot, ioh, NE7CMD_READ);		/* READ */
   1222 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1223 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
   1224 		out_fdc(iot, ioh, head);
   1225 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
   1226 		out_fdc(iot, ioh, type->secsize);	/* sector size */
   1227 		out_fdc(iot, ioh, type->sectrac);	/* sectors/track */
   1228 		out_fdc(iot, ioh, type->gap1);		/* gap1 size */
   1229 		out_fdc(iot, ioh, type->datalen);	/* data length */
   1230 		fdc->sc_state = COPYCOMPLETE;
   1231 		/* allow 2 seconds for operation */
   1232 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1233 		return 1;				/* will return later */
   1234 
   1235 	case DOIOHALF:
   1236 	doiohalf:
   1237 		DPRINTF((" DOIOHALF:\n"));
   1238 
   1239 		type = fd->sc_type;
   1240 		sectrac = type->sectrac;
   1241 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
   1242 		sec = pos / (1 << (type->secsize - 2));
   1243 		head = (fd->sc_blkno
   1244 			% (type->seccyl * (1 << (type->secsize - 2))))
   1245 			 / (type->sectrac * (1 << (type->secsize - 2)));
   1246 #ifdef DIAGNOSTIC
   1247 		{int block;
   1248 		 block = ((fd->sc_cylin * type->heads + head) *
   1249 			 type->sectrac + sec)
   1250 			 * (1 << (type->secsize - 2));
   1251 		 block += (fd->sc_part == SEC_P01) ? 1 : 0;
   1252 		 if (block != fd->sc_blkno) {
   1253 			 printf("fdcintr: block %d != blkno %" PRId64 "\n",
   1254 				block, fd->sc_blkno);
   1255 #ifdef DDB
   1256 			 Debugger();
   1257 #endif
   1258 		 }
   1259 		}
   1260 #endif
   1261 		if ((read = bp->b_flags & B_READ)) {
   1262 			memcpy((char *)bp->b_data + fd->sc_skip, fd->sc_copybuf
   1263 			    + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
   1264 			    FDC_BSIZE);
   1265 			fdc->sc_state = IOCOMPLETE;
   1266 			goto iocomplete2;
   1267 		} else {
   1268 			memcpy((char *)fd->sc_copybuf
   1269 			    + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
   1270 			    (char *)bp->b_data + fd->sc_skip, FDC_BSIZE);
   1271 			fdc_dmastart(fdc, read, fd->sc_copybuf, 1024);
   1272 		}
   1273 		out_fdc(iot, ioh, NE7CMD_WRITE);	/* WRITE */
   1274 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1275 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
   1276 		out_fdc(iot, ioh, head);
   1277 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
   1278 		out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */
   1279 		out_fdc(iot, ioh, sectrac);		/* sectors/track */
   1280 		out_fdc(iot, ioh, fd->sc_type->gap1);	/* gap1 size */
   1281 		out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */
   1282 		fdc->sc_state = IOCOMPLETE;
   1283 		/* allow 2 seconds for operation */
   1284 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1285 		return 1;				/* will return later */
   1286 
   1287 	case SEEKWAIT:
   1288 		callout_stop(&fdc->sc_timo_ch);
   1289 		fdc->sc_state = SEEKCOMPLETE;
   1290 		/* allow 1/50 second for heads to settle */
   1291 #if 0
   1292 		callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
   1293 #endif
   1294 		return 1;
   1295 
   1296 	case SEEKCOMPLETE:
   1297 		/* Make sure seek really happened */
   1298 		DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
   1299 			 bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts)));
   1300 		out_fdc(iot, ioh, NE7CMD_SENSEI);
   1301 		tmp = fdcresult(fdc);
   1302 		if ((st0 & 0xf8) == 0xc0) {
   1303 			DPRINTF(("fdcintr: first seek!\n"));
   1304 			fdc->sc_state = DORECAL;
   1305 			goto loop;
   1306 		} else if (tmp != 2 ||
   1307 			   (st0 & 0xf8) != 0x20 ||
   1308 			   cyl != bp->b_cylinder) {
   1309 #ifdef FDDEBUG
   1310 			fdcstatus(fd->sc_dev, 2, "seek failed");
   1311 #endif
   1312 			fdcretry(fdc);
   1313 			goto loop;
   1314 		}
   1315 		fd->sc_cylin = bp->b_cylinder;
   1316 		goto doio;
   1317 
   1318 	case IOTIMEDOUT:
   1319 #if 0
   1320 		isa_dmaabort(fdc->sc_drq);
   1321 #endif
   1322 	case SEEKTIMEDOUT:
   1323 	case RECALTIMEDOUT:
   1324 	case RESETTIMEDOUT:
   1325 		fdcretry(fdc);
   1326 		goto loop;
   1327 
   1328 	case IOCOMPLETE: /* IO DONE, post-analyze */
   1329 		callout_stop(&fdc->sc_timo_ch);
   1330 		DPRINTF(("fdcintr: in IOCOMPLETE\n"));
   1331 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
   1332 #if 0
   1333 			isa_dmaabort(fdc->sc_drq);
   1334 #endif
   1335 			fdcstatus(fd->sc_dev, tmp, bp->b_flags & B_READ ?
   1336 				  "read failed" : "write failed");
   1337 			printf("blkno %" PRId64 " nblks %d\n",
   1338 			    fd->sc_blkno, fd->sc_nblks);
   1339 			fdcretry(fdc);
   1340 			goto loop;
   1341 		}
   1342 #if 0
   1343 		isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
   1344 		    nblks * FDC_BSIZE, fdc->sc_drq);
   1345 #endif
   1346 	iocomplete2:
   1347 		if (fdc->sc_errors) {
   1348 			diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
   1349 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
   1350 			printf("\n");
   1351 			fdc->sc_errors = 0;
   1352 		}
   1353 		fd->sc_blkno += fd->sc_nblks;
   1354 		fd->sc_skip += fd->sc_nbytes;
   1355 		fd->sc_bcount -= fd->sc_nbytes;
   1356 		DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
   1357 		if (fd->sc_bcount > 0) {
   1358 			bp->b_cylinder = fd->sc_blkno
   1359 				/ (fd->sc_type->seccyl
   1360 				   * (1 << (fd->sc_type->secsize - 2)));
   1361 			goto doseek;
   1362 		}
   1363 		fdfinish(fd, bp);
   1364 		goto loop;
   1365 
   1366 	case COPYCOMPLETE: /* IO DONE, post-analyze */
   1367 		DPRINTF(("fdcintr: COPYCOMPLETE:"));
   1368 		callout_stop(&fdc->sc_timo_ch);
   1369 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
   1370 			printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
   1371 #if 0
   1372 			isa_dmaabort(fdc->sc_drq);
   1373 #endif
   1374 			fdcstatus(fd->sc_dev, 7, bp->b_flags & B_READ ?
   1375 				  "read failed" : "write failed");
   1376 			printf("blkno %" PRId64 " nblks %d\n",
   1377 			    fd->sc_blkno, fd->sc_nblks);
   1378 			fdcretry(fdc);
   1379 			goto loop;
   1380 		}
   1381 		goto doiohalf;
   1382 
   1383 	case DORESET:
   1384 		DPRINTF(("fdcintr: in DORESET\n"));
   1385 		/* try a reset, keep motor on */
   1386 		fd_set_motor(fdc, 1);
   1387 		DELAY(100);
   1388 		fd_set_motor(fdc, 0);
   1389 		fdc->sc_state = RESETCOMPLETE;
   1390 		callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
   1391 		return 1;			/* will return later */
   1392 
   1393 	case RESETCOMPLETE:
   1394 		DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
   1395 		callout_stop(&fdc->sc_timo_ch);
   1396 		/* clear the controller output buffer */
   1397 		for (i = 0; i < 4; i++) {
   1398 			out_fdc(iot, ioh, NE7CMD_SENSEI);
   1399 			(void) fdcresult(fdc);
   1400 		}
   1401 
   1402 		/* fall through */
   1403 	case DORECAL:
   1404 		DPRINTF(("fdcintr: in DORECAL\n"));
   1405 		out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
   1406 		out_fdc(iot, ioh, fd->sc_drive);
   1407 		fdc->sc_state = RECALWAIT;
   1408 		callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
   1409 		return 1;			/* will return later */
   1410 
   1411 	case RECALWAIT:
   1412 		DPRINTF(("fdcintr: in RECALWAIT\n"));
   1413 		callout_stop(&fdc->sc_timo_ch);
   1414 		fdc->sc_state = RECALCOMPLETE;
   1415 		/* allow 1/30 second for heads to settle */
   1416 #if 0
   1417 		callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
   1418 #endif
   1419 		return 1;			/* will return later */
   1420 
   1421 	case RECALCOMPLETE:
   1422 		DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
   1423 		out_fdc(iot, ioh, NE7CMD_SENSEI);
   1424 		tmp = fdcresult(fdc);
   1425 		if ((st0 & 0xf8) == 0xc0) {
   1426 			DPRINTF(("fdcintr: first seek!\n"));
   1427 			fdc->sc_state = DORECAL;
   1428 			goto loop;
   1429 		} else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
   1430 #ifdef FDDEBUG
   1431 			fdcstatus(fd->sc_dev, 2, "recalibrate failed");
   1432 #endif
   1433 			fdcretry(fdc);
   1434 			goto loop;
   1435 		}
   1436 		fd->sc_cylin = 0;
   1437 		goto doseek;
   1438 
   1439 	case MOTORWAIT:
   1440 		if (fd->sc_flags & FD_MOTOR_WAIT)
   1441 			return 1;		/* time's not up yet */
   1442 		goto doseek;
   1443 
   1444 	default:
   1445 		fdcstatus(fd->sc_dev, 0, "stray interrupt");
   1446 		return 1;
   1447 	}
   1448 #ifdef DIAGNOSTIC
   1449 	panic("fdcintr: impossible");
   1450 #endif
   1451 #undef	st0
   1452 #undef	cyl
   1453 }
   1454 
   1455 void
   1456 fdcretry(struct fdc_softc *fdc)
   1457 {
   1458 	struct fd_softc *fd;
   1459 	struct buf *bp;
   1460 
   1461 	DPRINTF(("fdcretry:\n"));
   1462 	fd = TAILQ_FIRST(&fdc->sc_drives);
   1463 	bp = bufq_peek(fd->sc_q);
   1464 
   1465 	switch (fdc->sc_errors) {
   1466 	case 0:
   1467 		/* try again */
   1468 		fdc->sc_state = SEEKCOMPLETE;
   1469 		break;
   1470 
   1471 	case 1: case 2: case 3:
   1472 		/* didn't work; try recalibrating */
   1473 		fdc->sc_state = DORECAL;
   1474 		break;
   1475 
   1476 	case 4:
   1477 		/* still no go; reset the bastard */
   1478 		fdc->sc_state = DORESET;
   1479 		break;
   1480 
   1481 	default:
   1482 		diskerr(bp, "fd", "hard error", LOG_PRINTF,
   1483 			fd->sc_skip, (struct disklabel *)NULL);
   1484 		fdcpstatus(7, fdc);
   1485 
   1486 		bp->b_error = EIO;
   1487 		fdfinish(fd, bp);
   1488 	}
   1489 	fdc->sc_errors++;
   1490 }
   1491 
   1492 int
   1493 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
   1494 {
   1495 	struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
   1496 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
   1497 	int part = DISKPART(dev);
   1498 	struct disklabel buffer;
   1499 	int error;
   1500 
   1501 	DPRINTF(("fdioctl:"));
   1502 	switch (cmd) {
   1503 	case DIOCGDINFO:
   1504 		DPRINTF(("DIOCGDINFO\n"));
   1505 #if 1
   1506 		*(struct disklabel *)addr = *(fd->sc_dk.dk_label);
   1507 		return(0);
   1508 #else
   1509 		memset(&buffer, 0, sizeof(buffer));
   1510 
   1511 		buffer.d_secpercyl = fd->sc_type->seccyl;
   1512 		buffer.d_type = DTYPE_FLOPPY;
   1513 		buffer.d_secsize = 128 << fd->sc_type->secsize;
   1514 
   1515 		if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
   1516 			return EINVAL;
   1517 
   1518 		*(struct disklabel *)addr = buffer;
   1519 		return 0;
   1520 #endif
   1521 
   1522 	case DIOCGPART:
   1523 		DPRINTF(("DIOCGPART\n"));
   1524 		((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
   1525 		((struct partinfo *)addr)->part =
   1526 		    &fd->sc_dk.dk_label->d_partitions[part];
   1527 		return(0);
   1528 
   1529 	case DIOCWLABEL:
   1530 		DPRINTF(("DIOCWLABEL\n"));
   1531 		if ((flag & FWRITE) == 0)
   1532 			return EBADF;
   1533 		/* XXX do something */
   1534 		return 0;
   1535 
   1536 	case DIOCWDINFO:
   1537 		DPRINTF(("DIOCWDINFO\n"));
   1538 		if ((flag & FWRITE) == 0)
   1539 			return EBADF;
   1540 
   1541 		error = setdisklabel(&buffer, (struct disklabel *)addr,
   1542 		                     0, NULL);
   1543 		if (error)
   1544 			return error;
   1545 
   1546 		error = writedisklabel(dev, fdstrategy, &buffer, NULL);
   1547 		return error;
   1548 
   1549 	case DIOCLOCK:
   1550 		/*
   1551 		 * Nothing to do here, really.
   1552 		 */
   1553 		return 0; /* XXX */
   1554 
   1555 	case DIOCEJECT:
   1556 		DPRINTF(("DIOCEJECT\n"));
   1557 		if (*(int *)addr == 0) {
   1558 			/*
   1559 			 * Don't force eject: check that we are the only
   1560 			 * partition open. If so, unlock it.
   1561 			 */
   1562 			if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 ||
   1563 			    fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask !=
   1564 			    fd->sc_dk.dk_openmask) {
   1565 				return (EBUSY);
   1566 			}
   1567 		}
   1568 		/* FALLTHROUGH */
   1569 	case ODIOCEJECT:
   1570 		DPRINTF(("ODIOCEJECT\n"));
   1571 		fd_do_eject(fdc, FDUNIT(dev));
   1572 		return 0;
   1573 
   1574 	default:
   1575 		return ENOTTY;
   1576 	}
   1577 
   1578 #ifdef DIAGNOSTIC
   1579 	panic("fdioctl: impossible");
   1580 #endif
   1581 }
   1582 
   1583 void
   1584 fd_do_eject(struct fdc_softc *fdc, int unit)
   1585 {
   1586 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
   1587 			  0x20 | ( 1 << unit));
   1588 	DELAY(1); /* XXX */
   1589 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20);
   1590 }
   1591 
   1592 /*
   1593  * Build disk label. For now we only create a label from what we know
   1594  * from 'sc'.
   1595  */
   1596 static int
   1597 fdgetdisklabel(struct fd_softc *sc, dev_t dev)
   1598 {
   1599 	struct disklabel *lp;
   1600 	int part;
   1601 
   1602 	DPRINTF(("fdgetdisklabel()\n"));
   1603 
   1604 	part = DISKPART(dev);
   1605 	lp = sc->sc_dk.dk_label;
   1606 	memset(lp, 0, sizeof(struct disklabel));
   1607 
   1608 	lp->d_secsize     = 128 << sc->sc_type->secsize;
   1609 	lp->d_ntracks     = sc->sc_type->heads;
   1610 	lp->d_nsectors    = sc->sc_type->sectrac;
   1611 	lp->d_secpercyl   = lp->d_ntracks * lp->d_nsectors;
   1612 	lp->d_ncylinders  = sc->sc_type->size / lp->d_secpercyl;
   1613 	lp->d_secperunit  = sc->sc_type->size;
   1614 
   1615 	lp->d_type        = DTYPE_FLOPPY;
   1616 	lp->d_rpm         = 300; 	/* XXX */
   1617 	lp->d_interleave  = 1;		/* FIXME: is this OK?		*/
   1618 	lp->d_bbsize      = 0;
   1619 	lp->d_sbsize      = 0;
   1620 	lp->d_npartitions = part + 1;
   1621 #define STEP_DELAY	6000	/* 6ms (6000us) delay after stepping	*/
   1622 	lp->d_trkseek     = STEP_DELAY; /* XXX */
   1623 	lp->d_magic       = DISKMAGIC;
   1624 	lp->d_magic2      = DISKMAGIC;
   1625 	lp->d_checksum    = dkcksum(lp);
   1626 	lp->d_partitions[part].p_size   = lp->d_secperunit;
   1627 	lp->d_partitions[part].p_fstype = FS_UNUSED;
   1628 	lp->d_partitions[part].p_fsize  = 1024;
   1629 	lp->d_partitions[part].p_frag   = 8;
   1630 
   1631 	return(0);
   1632 }
   1633 
   1634 /*
   1635  * Mountroot hook: prompt the user to enter the root file system
   1636  * floppy.
   1637  */
   1638 void
   1639 fd_mountroot_hook(device_t dev)
   1640 {
   1641 	struct fd_softc *fd = device_private(dev);
   1642 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
   1643 	int c;
   1644 
   1645 	/* XXX device_unit() abuse */
   1646 	fd_do_eject(fdc, device_unit(dev));
   1647 	printf("Insert filesystem floppy and press return.");
   1648 	for (;;) {
   1649 		c = cngetc();
   1650 		if ((c == '\r') || (c == '\n')) {
   1651 			printf("\n");
   1652 			break;
   1653 		}
   1654 	}
   1655 }
   1656