Home | History | Annotate | Line # | Download | only in dev
fd.c revision 1.83
      1 /*	$NetBSD: fd.c,v 1.83 2008/06/25 08:14:59 isaki 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.83 2008/06/25 08:14:59 isaki Exp $");
     68 
     69 #include "rnd.h"
     70 #include "opt_ddb.h"
     71 #include "opt_m680x0.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 <machine/bus.h>
     98 #include <machine/cpu.h>
     99 
    100 #include <arch/x68k/dev/intiovar.h>
    101 #include <arch/x68k/dev/dmacvar.h>
    102 #include <arch/x68k/dev/fdreg.h>
    103 #include <arch/x68k/dev/opmvar.h> /* for CT1 access */
    104 
    105 #include "locators.h"
    106 
    107 #ifdef FDDEBUG
    108 #define DPRINTF(x)      if (fddebug) printf x
    109 int     fddebug = 0;
    110 #else
    111 #define DPRINTF(x)
    112 #endif
    113 
    114 #define FDUNIT(dev)	(minor(dev) / 8)
    115 #define FDTYPE(dev)	(minor(dev) % 8)
    116 
    117 enum fdc_state {
    118 	DEVIDLE = 0,
    119 	MOTORWAIT,
    120 	DOSEEK,
    121 	SEEKWAIT,
    122 	SEEKTIMEDOUT,
    123 	SEEKCOMPLETE,
    124 	DOIO,
    125 	IOCOMPLETE,
    126 	IOTIMEDOUT,
    127 	DORESET,
    128 	RESETCOMPLETE,
    129 	RESETTIMEDOUT,
    130 	DORECAL,
    131 	RECALWAIT,
    132 	RECALTIMEDOUT,
    133 	RECALCOMPLETE,
    134 	DOCOPY,
    135 	DOIOHALF,
    136 	COPYCOMPLETE,
    137 };
    138 
    139 /* software state, per controller */
    140 struct fdc_softc {
    141 	device_t sc_dev;		/* boilerplate */
    142 
    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_flags = 0;
    571 
    572 	if (type)
    573 		aprint_normal(": %s, %d cyl, %d head, %d sec\n", type->name,
    574 		       type->cyls, type->heads, type->sectrac);
    575 	else
    576 		aprint_normal(": density unknown\n");
    577 
    578 	bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER);
    579 	fd->sc_cylin = -1;
    580 	fd->sc_drive = drive;
    581 	fd->sc_deftype = type;
    582 	fdc->sc_fd[drive] = fd;
    583 
    584 	fd->sc_copybuf = (u_char *)malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK);
    585 	if (fd->sc_copybuf == 0)
    586 		aprint_error("%s: WARNING!! malloc() failed.\n", __func__);
    587 	fd->sc_flags |= FD_ALIVE;
    588 
    589 	/*
    590 	 * Initialize and attach the disk structure.
    591 	 */
    592 	disk_init(&fd->sc_dk, device_xname(fd->sc_dev), &fddkdriver);
    593 	disk_attach(&fd->sc_dk);
    594 
    595 	/*
    596 	 * Establish a mountroot_hook anyway in case we booted
    597 	 * with RB_ASKNAME and get selected as the boot device.
    598 	 */
    599 	mountroothook_establish(fd_mountroot_hook, fd->sc_dev);
    600 
    601 #if NRND > 0
    602 	rnd_attach_source(&fd->rnd_source, device_xname(fd->sc_dev),
    603 			  RND_TYPE_DISK, 0);
    604 #endif
    605 }
    606 
    607 inline struct fd_type *
    608 fd_dev_to_type(struct fd_softc *fd, dev_t dev)
    609 {
    610 	int type = FDTYPE(dev);
    611 
    612 	if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
    613 		return NULL;
    614 	return &fd_types[type];
    615 }
    616 
    617 void
    618 fdstrategy(struct buf *bp)
    619 {
    620 	struct fd_softc *fd;
    621 	int sz;
    622 	int s;
    623 
    624 	fd = device_lookup_private(&fd_cd, FDUNIT(bp->b_dev));
    625 	if (fd == NULL) {
    626 		bp->b_error = EINVAL;
    627 		goto done;
    628 	}
    629 
    630 	if (bp->b_blkno < 0 ||
    631 	    (bp->b_bcount % FDC_BSIZE) != 0) {
    632 		DPRINTF(("fdstrategy: unit=%d, blkno=%" PRId64 ", "
    633 			 "bcount=%d\n", unit,
    634 			 bp->b_blkno, bp->b_bcount));
    635 		bp->b_error = EINVAL;
    636 		goto done;
    637 	}
    638 
    639 	/* If it's a null transfer, return immediately. */
    640 	if (bp->b_bcount == 0)
    641 		goto done;
    642 
    643 	sz = howmany(bp->b_bcount, FDC_BSIZE);
    644 
    645 	if (bp->b_blkno + sz >
    646 	    (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
    647 		sz = (fd->sc_type->size << (fd->sc_type->secsize - 2))
    648 		     - bp->b_blkno;
    649 		if (sz == 0) {
    650 			/* If exactly at end of disk, return EOF. */
    651 			bp->b_resid = bp->b_bcount;
    652 			goto done;
    653 		}
    654 		if (sz < 0) {
    655 			/* If past end of disk, return EINVAL. */
    656 			bp->b_error = EINVAL;
    657 			goto done;
    658 		}
    659 		/* Otherwise, truncate request. */
    660 		bp->b_bcount = sz << DEV_BSHIFT;
    661 	}
    662 
    663 	bp->b_rawblkno = bp->b_blkno;
    664 	bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)
    665 		/ (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2)));
    666 
    667 	DPRINTF(("fdstrategy: %s b_blkno %" PRId64 " b_bcount %d cylin %d\n",
    668 		 bp->b_flags & B_READ ? "read" : "write",
    669 		 bp->b_blkno, bp->b_bcount, bp->b_cylinder));
    670 	/* Queue transfer on drive, activate drive and controller if idle. */
    671 	s = splbio();
    672 	BUFQ_PUT(fd->sc_q, bp);
    673 	callout_stop(&fd->sc_motoroff_ch);		/* a good idea */
    674 	if (fd->sc_active == 0)
    675 		fdstart(fd);
    676 #ifdef DIAGNOSTIC
    677 	else {
    678 		struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
    679 		if (fdc->sc_state == DEVIDLE) {
    680 			printf("fdstrategy: controller inactive\n");
    681 			fdcstart(fdc);
    682 		}
    683 	}
    684 #endif
    685 	splx(s);
    686 	return;
    687 
    688 done:
    689 	/* Toss transfer; we're done early. */
    690 	biodone(bp);
    691 }
    692 
    693 void
    694 fdstart(struct fd_softc *fd)
    695 {
    696 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
    697 	int active = fdc->sc_drives.tqh_first != 0;
    698 
    699 	/* Link into controller queue. */
    700 	fd->sc_active = 1;
    701 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    702 
    703 	/* If controller not already active, start it. */
    704 	if (!active)
    705 		fdcstart(fdc);
    706 }
    707 
    708 void
    709 fdfinish(struct fd_softc *fd, struct buf *bp)
    710 {
    711 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
    712 
    713 	/*
    714 	 * Move this drive to the end of the queue to give others a `fair'
    715 	 * chance.  We only force a switch if N operations are completed while
    716 	 * another drive is waiting to be serviced, since there is a long motor
    717 	 * startup delay whenever we switch.
    718 	 */
    719 	(void)BUFQ_GET(fd->sc_q);
    720 	if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
    721 		fd->sc_ops = 0;
    722 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
    723 		if (BUFQ_PEEK(fd->sc_q) != NULL) {
    724 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    725 		} else
    726 			fd->sc_active = 0;
    727 	}
    728 	bp->b_resid = fd->sc_bcount;
    729 	fd->sc_skip = 0;
    730 
    731 #if NRND > 0
    732 	rnd_add_uint32(&fd->rnd_source, bp->b_blkno);
    733 #endif
    734 
    735 	biodone(bp);
    736 	/* turn off motor 5s from now */
    737 	callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
    738 	fdc->sc_state = DEVIDLE;
    739 }
    740 
    741 int
    742 fdread(dev_t dev, struct uio *uio, int flags)
    743 {
    744 
    745 	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
    746 }
    747 
    748 int
    749 fdwrite(dev_t dev, struct uio *uio, int flags)
    750 {
    751 
    752 	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
    753 }
    754 
    755 void
    756 fd_set_motor(struct fdc_softc *fdc, int reset)
    757 {
    758 	struct fd_softc *fd;
    759 	int n;
    760 
    761 	DPRINTF(("fd_set_motor:\n"));
    762 	for (n = 0; n < 4; n++)
    763 		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) {
    764 			bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl,
    765 					  0x80 | (fd->sc_type->rate << 4)| n);
    766 		}
    767 }
    768 
    769 void
    770 fd_motor_off(void *arg)
    771 {
    772 	struct fd_softc *fd = arg;
    773  	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
    774 	int s;
    775 
    776 	DPRINTF(("fd_motor_off:\n"));
    777 
    778 	s = splbio();
    779 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
    780 	bus_space_write_1 (fdc->sc_iot, fdc->sc_ioh, fdctl,
    781 			   (fd->sc_type->rate << 4) | fd->sc_drive);
    782 #if 0
    783 	fd_set_motor(fdc, 0); /* XXX */
    784 #endif
    785 	splx(s);
    786 }
    787 
    788 void
    789 fd_motor_on(void *arg)
    790 {
    791 	struct fd_softc *fd = arg;
    792 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
    793 	int s;
    794 
    795 	DPRINTF(("fd_motor_on:\n"));
    796 
    797 	s = splbio();
    798 	fd->sc_flags &= ~FD_MOTOR_WAIT;
    799 	if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
    800 		(void) fdcintr(fdc);
    801 	splx(s);
    802 }
    803 
    804 int
    805 fdcresult(struct fdc_softc *fdc)
    806 {
    807 	bus_space_tag_t iot = fdc->sc_iot;
    808 	bus_space_handle_t ioh = fdc->sc_ioh;
    809 	u_char i;
    810 	int j = 100000,
    811 	    n = 0;
    812 
    813 	for (; j; j--) {
    814 		i = bus_space_read_1(iot, ioh, fdsts) &
    815 		  (NE7_DIO | NE7_RQM | NE7_CB);
    816 
    817 		if (i == NE7_RQM)
    818 			return n;
    819 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
    820 			if (n >= sizeof(fdc->sc_status)) {
    821 				log(LOG_ERR, "fdcresult: overrun\n");
    822 				return -1;
    823 			}
    824 			fdc->sc_status[n++] =
    825 			  bus_space_read_1(iot, ioh, fddata);
    826 		}
    827 		delay(10);
    828 	}
    829 	log(LOG_ERR, "fdcresult: timeout\n");
    830 	return -1;
    831 }
    832 
    833 int
    834 out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x)
    835 {
    836 	int i = 100000;
    837 
    838 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
    839 	if (i <= 0)
    840 		return -1;
    841 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
    842 	if (i <= 0)
    843 		return -1;
    844 	bus_space_write_1(iot, ioh, fddata, x);
    845 	return 0;
    846 }
    847 
    848 int
    849 fdopen(dev_t dev, int flags, int mode, struct lwp *l)
    850 {
    851 	int unit;
    852 	struct fd_softc *fd;
    853 	struct fd_type *type;
    854 	struct fdc_softc *fdc;
    855 
    856 	unit = FDUNIT(dev);
    857 	fd = device_lookup_private(&fd_cd, unit);
    858 	if (fd == NULL)
    859 		return ENXIO;
    860 	type = fd_dev_to_type(fd, dev);
    861 	if (type == NULL)
    862 		return ENXIO;
    863 
    864 	if ((fd->sc_flags & FD_OPEN) != 0 &&
    865 	    fd->sc_type != type)
    866 		return EBUSY;
    867 
    868 	fdc = device_private(device_parent(fd->sc_dev));
    869 	if ((fd->sc_flags & FD_OPEN) == 0) {
    870 		/* Lock eject button */
    871 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
    872 				  0x40 | ( 1 << unit));
    873 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x40);
    874 	}
    875 
    876 	fd->sc_type = type;
    877 	fd->sc_cylin = -1;
    878 
    879 	switch (mode) {
    880 	case S_IFCHR:
    881 		fd->sc_flags |= FD_COPEN;
    882 		break;
    883 	case S_IFBLK:
    884 		fd->sc_flags |= FD_BOPEN;
    885 		break;
    886 	}
    887 
    888 	fdgetdisklabel(fd, dev);
    889 
    890 	return 0;
    891 }
    892 
    893 int
    894 fdclose(dev_t dev, int flags, int mode, struct lwp *l)
    895 {
    896 	int unit = FDUNIT(dev);
    897 	struct fd_softc *fd = device_lookup_private(&fd_cd, unit);
    898 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
    899 
    900 	DPRINTF(("fdclose %d\n", unit));
    901 
    902 	switch (mode) {
    903 	case S_IFCHR:
    904 		fd->sc_flags &= ~FD_COPEN;
    905 		break;
    906 	case S_IFBLK:
    907 		fd->sc_flags &= ~FD_BOPEN;
    908 		break;
    909 	}
    910 
    911 	if ((fd->sc_flags & FD_OPEN) == 0) {
    912 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
    913 				  ( 1 << unit));
    914 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0);
    915 	}
    916 	return 0;
    917 }
    918 
    919 void
    920 fdcstart(struct fdc_softc *fdc)
    921 {
    922 
    923 #ifdef DIAGNOSTIC
    924 	/* only got here if controller's drive queue was inactive; should
    925 	   be in idle state */
    926 	if (fdc->sc_state != DEVIDLE) {
    927 		printf("fdcstart: not idle\n");
    928 		return;
    929 	}
    930 #endif
    931 	(void) fdcintr(fdc);
    932 }
    933 
    934 void
    935 fdcstatus(device_t dv, int n, const char *s)
    936 {
    937 	struct fdc_softc *fdc = device_private(device_parent(dv));
    938 	char bits[64];
    939 
    940 	if (n == 0) {
    941 		out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
    942 		(void) fdcresult(fdc);
    943 		n = 2;
    944 	}
    945 
    946 	printf("%s: %s: state %d", device_xname(dv), s, fdc->sc_state);
    947 
    948 	switch (n) {
    949 	case 0:
    950 		printf("\n");
    951 		break;
    952 	case 2:
    953 		printf(" (st0 %s cyl %d)\n",
    954 		    bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
    955 		    bits, sizeof(bits)), fdc->sc_status[1]);
    956 		break;
    957 	case 7:
    958 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
    959 		    NE7_ST0BITS, bits, sizeof(bits)));
    960 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
    961 		    NE7_ST1BITS, bits, sizeof(bits)));
    962 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
    963 		    NE7_ST2BITS, bits, sizeof(bits)));
    964 		printf(" cyl %d head %d sec %d)\n",
    965 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
    966 		break;
    967 #ifdef DIAGNOSTIC
    968 	default:
    969 		printf(" fdcstatus: weird size: %d\n", n);
    970 		break;
    971 #endif
    972 	}
    973 }
    974 
    975 void
    976 fdctimeout(void *arg)
    977 {
    978 	struct fdc_softc *fdc = arg;
    979 	struct fd_softc *fd = fdc->sc_drives.tqh_first;
    980 	int s;
    981 
    982 	s = splbio();
    983 	fdcstatus(fd->sc_dev, 0, "timeout");
    984 
    985 	if (BUFQ_PEEK(fd->sc_q) != NULL)
    986 		fdc->sc_state++;
    987 	else
    988 		fdc->sc_state = DEVIDLE;
    989 
    990 	(void) fdcintr(fdc);
    991 	splx(s);
    992 }
    993 
    994 #if 0
    995 void
    996 fdcpseudointr(void *arg)
    997 {
    998 	int s;
    999 	struct fdc_softc *fdc = arg;
   1000 
   1001 	/* just ensure it has the right spl */
   1002 	s = splbio();
   1003 	(void) fdcintr(fdc);
   1004 	splx(s);
   1005 }
   1006 #endif
   1007 
   1008 int
   1009 fdcintr(void *arg)
   1010 {
   1011 	struct fdc_softc *fdc = arg;
   1012 #define	st0	fdc->sc_status[0]
   1013 #define	cyl	fdc->sc_status[1]
   1014 	struct fd_softc *fd;
   1015 	struct buf *bp;
   1016 	bus_space_tag_t iot = fdc->sc_iot;
   1017 	bus_space_handle_t ioh = fdc->sc_ioh;
   1018 	int read, head, sec, pos, i, sectrac, nblks;
   1019 	int	tmp;
   1020 	struct fd_type *type;
   1021 
   1022 loop:
   1023 	fd = fdc->sc_drives.tqh_first;
   1024 	if (fd == NULL) {
   1025 		DPRINTF(("fdcintr: set DEVIDLE\n"));
   1026 		if (fdc->sc_state == DEVIDLE) {
   1027 			if (intio_get_sicilian_intr() & SICILIAN_STAT_FDC) {
   1028 				out_fdc(iot, ioh, NE7CMD_SENSEI);
   1029 				if ((tmp = fdcresult(fdc)) != 2 ||
   1030 				    (st0 & 0xf8) != 0x20) {
   1031 					goto loop;
   1032 				}
   1033 			}
   1034 		}
   1035 		/* no drives waiting; end */
   1036 		fdc->sc_state = DEVIDLE;
   1037 		return 1;
   1038 	}
   1039 
   1040 	/* Is there a transfer to this drive?  If not, deactivate drive. */
   1041 	bp = BUFQ_PEEK(fd->sc_q);
   1042 	if (bp == NULL) {
   1043 		fd->sc_ops = 0;
   1044 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
   1045 		fd->sc_active = 0;
   1046 		goto loop;
   1047 	}
   1048 
   1049 	switch (fdc->sc_state) {
   1050 	case DEVIDLE:
   1051 		DPRINTF(("fdcintr: in DEVIDLE\n"));
   1052 		fdc->sc_errors = 0;
   1053 		fd->sc_skip = 0;
   1054 		fd->sc_bcount = bp->b_bcount;
   1055 		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
   1056 		callout_stop(&fd->sc_motoroff_ch);
   1057 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
   1058 			fdc->sc_state = MOTORWAIT;
   1059 			return 1;
   1060 		}
   1061 		if ((fd->sc_flags & FD_MOTOR) == 0) {
   1062 			/* Turn on the motor */
   1063 			/* being careful about other drives. */
   1064 			for (i = 0; i < 4; i++) {
   1065 				struct fd_softc *ofd = fdc->sc_fd[i];
   1066 				if (ofd && ofd->sc_flags & FD_MOTOR) {
   1067 					callout_stop(&ofd->sc_motoroff_ch);
   1068 					ofd->sc_flags &=
   1069 						~(FD_MOTOR | FD_MOTOR_WAIT);
   1070 					break;
   1071 				}
   1072 			}
   1073 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
   1074 			fd_set_motor(fdc, 0);
   1075 			fdc->sc_state = MOTORWAIT;
   1076 			/* allow .5s for motor to stabilize */
   1077 			callout_reset(&fd->sc_motoron_ch, hz / 2,
   1078 			    fd_motor_on, fd);
   1079 			return 1;
   1080 		}
   1081 		/* Make sure the right drive is selected. */
   1082 		fd_set_motor(fdc, 0);
   1083 
   1084 		/* fall through */
   1085 	case DOSEEK:
   1086 	doseek:
   1087 		DPRINTF(("fdcintr: in DOSEEK\n"));
   1088 		if (fd->sc_cylin == bp->b_cylinder)
   1089 			goto doio;
   1090 
   1091 		out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
   1092 		out_fdc(iot, ioh, 0xd0);	/* XXX const */
   1093 		out_fdc(iot, ioh, 0x10);
   1094 
   1095 		out_fdc(iot, ioh, NE7CMD_SEEK);	/* seek function */
   1096 		out_fdc(iot, ioh, fd->sc_drive);	/* drive number */
   1097 		out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
   1098 
   1099 		fd->sc_cylin = -1;
   1100 		fdc->sc_state = SEEKWAIT;
   1101 
   1102 		iostat_seek(fd->sc_dk.dk_stats);
   1103 		disk_busy(&fd->sc_dk);
   1104 
   1105 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
   1106 		return 1;
   1107 
   1108 	case DOIO:
   1109 	doio:
   1110 		DPRINTF(("fdcintr: DOIO: "));
   1111 		type = fd->sc_type;
   1112 		sectrac = type->sectrac;
   1113 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
   1114 		sec = pos / (1 << (type->secsize - 2));
   1115 		if (type->secsize == 2) {
   1116 			fd->sc_part = SEC_P11;
   1117 			nblks = (sectrac - sec) << (type->secsize - 2);
   1118 			nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
   1119 			DPRINTF(("nblks(0)"));
   1120 		} else if ((fd->sc_blkno % 2) == 0) {
   1121 			if (fd->sc_bcount & 0x00000200) {
   1122 				if (fd->sc_bcount == FDC_BSIZE) {
   1123 					fd->sc_part = SEC_P10;
   1124 					nblks = 1;
   1125 					DPRINTF(("nblks(1)"));
   1126 				} else {
   1127 					fd->sc_part = SEC_P11;
   1128 					nblks = (sectrac - sec) * 2;
   1129 					nblks = min(nblks, fd->sc_bcount
   1130 						    / FDC_BSIZE - 1);
   1131 					DPRINTF(("nblks(2)"));
   1132 				}
   1133 			} else {
   1134 				fd->sc_part = SEC_P11;
   1135 				nblks = (sectrac - sec)
   1136 					<< (type->secsize - 2);
   1137 				nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
   1138 				DPRINTF(("nblks(3)"));
   1139 			}
   1140 		} else {
   1141 			fd->sc_part = SEC_P01;
   1142 			nblks = 1;
   1143 			DPRINTF(("nblks(4)"));
   1144 		}
   1145 		nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
   1146 		DPRINTF((" %d\n", nblks));
   1147 		fd->sc_nblks = nblks;
   1148 		fd->sc_nbytes = nblks * FDC_BSIZE;
   1149 		head = (fd->sc_blkno
   1150 			% (type->seccyl * (1 << (type->secsize - 2))))
   1151 			 / (type->sectrac * (1 << (type->secsize - 2)));
   1152 
   1153 #ifdef DIAGNOSTIC
   1154 		{int block;
   1155 		 block = ((fd->sc_cylin * type->heads + head) * type->sectrac
   1156 			  + sec) * (1 << (type->secsize - 2));
   1157 		 block += (fd->sc_part == SEC_P01) ? 1 : 0;
   1158 		 if (block != fd->sc_blkno) {
   1159 			 printf("C H R N: %d %d %d %d\n",
   1160 				fd->sc_cylin, head, sec, type->secsize);
   1161 			 printf("fdcintr: doio: block %d != blkno %" PRId64 "\n",
   1162 				block, fd->sc_blkno);
   1163 #ifdef DDB
   1164 			 Debugger();
   1165 #endif
   1166 		 }
   1167 		}
   1168 #endif
   1169 		read = bp->b_flags & B_READ;
   1170 		DPRINTF(("fdcintr: %s drive %d track %d "
   1171 		         "head %d sec %d nblks %d, skip %d\n",
   1172 			 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
   1173 			 head, sec, nblks, fd->sc_skip));
   1174 		DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
   1175 			 type->secsize));
   1176 
   1177 		if (fd->sc_part != SEC_P11)
   1178 			goto docopy;
   1179 
   1180 		fdc_dmastart(fdc, read, (char *)bp->b_data + fd->sc_skip,
   1181 			     fd->sc_nbytes);
   1182 		if (read)
   1183 			out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
   1184 		else
   1185 			out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
   1186 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1187 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
   1188 		out_fdc(iot, ioh, head);
   1189 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
   1190 		out_fdc(iot, ioh, type->secsize);	/* sector size */
   1191 		out_fdc(iot, ioh, type->sectrac);	/* sectors/track */
   1192 		out_fdc(iot, ioh, type->gap1);		/* gap1 size */
   1193 		out_fdc(iot, ioh, type->datalen);	/* data length */
   1194 		fdc->sc_state = IOCOMPLETE;
   1195 
   1196 		disk_busy(&fd->sc_dk);
   1197 
   1198 		/* allow 2 seconds for operation */
   1199 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1200 		return 1;				/* will return later */
   1201 
   1202 	case DOCOPY:
   1203 	docopy:
   1204 		DPRINTF(("fdcintr: DOCOPY:\n"));
   1205 		type = fd->sc_type;
   1206 		head = (fd->sc_blkno
   1207 			% (type->seccyl * (1 << (type->secsize - 2))))
   1208 			 / (type->sectrac * (1 << (type->secsize - 2)));
   1209 		pos = fd->sc_blkno % (type->sectrac * (1 << (type->secsize - 2)));
   1210 		sec = pos / (1 << (type->secsize - 2));
   1211 		fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024);
   1212 		out_fdc(iot, ioh, NE7CMD_READ);		/* READ */
   1213 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1214 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
   1215 		out_fdc(iot, ioh, head);
   1216 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
   1217 		out_fdc(iot, ioh, type->secsize);	/* sector size */
   1218 		out_fdc(iot, ioh, type->sectrac);	/* sectors/track */
   1219 		out_fdc(iot, ioh, type->gap1);		/* gap1 size */
   1220 		out_fdc(iot, ioh, type->datalen);	/* data length */
   1221 		fdc->sc_state = COPYCOMPLETE;
   1222 		/* allow 2 seconds for operation */
   1223 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1224 		return 1;				/* will return later */
   1225 
   1226 	case DOIOHALF:
   1227 	doiohalf:
   1228 		DPRINTF((" DOIOHALF:\n"));
   1229 
   1230 		type = fd->sc_type;
   1231 		sectrac = type->sectrac;
   1232 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
   1233 		sec = pos / (1 << (type->secsize - 2));
   1234 		head = (fd->sc_blkno
   1235 			% (type->seccyl * (1 << (type->secsize - 2))))
   1236 			 / (type->sectrac * (1 << (type->secsize - 2)));
   1237 #ifdef DIAGNOSTIC
   1238 		{int block;
   1239 		 block = ((fd->sc_cylin * type->heads + head) *
   1240 			 type->sectrac + sec)
   1241 			 * (1 << (type->secsize - 2));
   1242 		 block += (fd->sc_part == SEC_P01) ? 1 : 0;
   1243 		 if (block != fd->sc_blkno) {
   1244 			 printf("fdcintr: block %d != blkno %" PRId64 "\n",
   1245 				block, fd->sc_blkno);
   1246 #ifdef DDB
   1247 			 Debugger();
   1248 #endif
   1249 		 }
   1250 		}
   1251 #endif
   1252 		if ((read = bp->b_flags & B_READ)) {
   1253 			memcpy((char *)bp->b_data + fd->sc_skip, fd->sc_copybuf
   1254 			    + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
   1255 			    FDC_BSIZE);
   1256 			fdc->sc_state = IOCOMPLETE;
   1257 			goto iocomplete2;
   1258 		} else {
   1259 			memcpy((char *)fd->sc_copybuf
   1260 			    + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
   1261 			    (char *)bp->b_data + fd->sc_skip, FDC_BSIZE);
   1262 			fdc_dmastart(fdc, read, fd->sc_copybuf, 1024);
   1263 		}
   1264 		out_fdc(iot, ioh, NE7CMD_WRITE);	/* WRITE */
   1265 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1266 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
   1267 		out_fdc(iot, ioh, head);
   1268 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
   1269 		out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */
   1270 		out_fdc(iot, ioh, sectrac);		/* sectors/track */
   1271 		out_fdc(iot, ioh, fd->sc_type->gap1);	/* gap1 size */
   1272 		out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */
   1273 		fdc->sc_state = IOCOMPLETE;
   1274 		/* allow 2 seconds for operation */
   1275 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1276 		return 1;				/* will return later */
   1277 
   1278 	case SEEKWAIT:
   1279 		callout_stop(&fdc->sc_timo_ch);
   1280 		fdc->sc_state = SEEKCOMPLETE;
   1281 		/* allow 1/50 second for heads to settle */
   1282 #if 0
   1283 		callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
   1284 #endif
   1285 		return 1;
   1286 
   1287 	case SEEKCOMPLETE:
   1288 		/* Make sure seek really happened */
   1289 		DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
   1290 			 bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts)));
   1291 		out_fdc(iot, ioh, NE7CMD_SENSEI);
   1292 		tmp = fdcresult(fdc);
   1293 		if ((st0 & 0xf8) == 0xc0) {
   1294 			DPRINTF(("fdcintr: first seek!\n"));
   1295 			fdc->sc_state = DORECAL;
   1296 			goto loop;
   1297 		} else if (tmp != 2 ||
   1298 			   (st0 & 0xf8) != 0x20 ||
   1299 			   cyl != bp->b_cylinder) {
   1300 #ifdef FDDEBUG
   1301 			fdcstatus(fd->sc_dev, 2, "seek failed");
   1302 #endif
   1303 			fdcretry(fdc);
   1304 			goto loop;
   1305 		}
   1306 		fd->sc_cylin = bp->b_cylinder;
   1307 		goto doio;
   1308 
   1309 	case IOTIMEDOUT:
   1310 #if 0
   1311 		isa_dmaabort(fdc->sc_drq);
   1312 #endif
   1313 	case SEEKTIMEDOUT:
   1314 	case RECALTIMEDOUT:
   1315 	case RESETTIMEDOUT:
   1316 		fdcretry(fdc);
   1317 		goto loop;
   1318 
   1319 	case IOCOMPLETE: /* IO DONE, post-analyze */
   1320 		callout_stop(&fdc->sc_timo_ch);
   1321 		DPRINTF(("fdcintr: in IOCOMPLETE\n"));
   1322 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
   1323 			printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
   1324 #if 0
   1325 			isa_dmaabort(fdc->sc_drq);
   1326 #endif
   1327 			fdcstatus(fd->sc_dev, 7, bp->b_flags & B_READ ?
   1328 				  "read failed" : "write failed");
   1329 			printf("blkno %" PRId64 " nblks %d\n",
   1330 			    fd->sc_blkno, fd->sc_nblks);
   1331 			fdcretry(fdc);
   1332 			goto loop;
   1333 		}
   1334 #if 0
   1335 		isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
   1336 		    nblks * FDC_BSIZE, fdc->sc_drq);
   1337 #endif
   1338 	iocomplete2:
   1339 		if (fdc->sc_errors) {
   1340 			diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
   1341 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
   1342 			printf("\n");
   1343 			fdc->sc_errors = 0;
   1344 		}
   1345 		fd->sc_blkno += fd->sc_nblks;
   1346 		fd->sc_skip += fd->sc_nbytes;
   1347 		fd->sc_bcount -= fd->sc_nbytes;
   1348 		DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
   1349 		if (fd->sc_bcount > 0) {
   1350 			bp->b_cylinder = fd->sc_blkno
   1351 				/ (fd->sc_type->seccyl
   1352 				   * (1 << (fd->sc_type->secsize - 2)));
   1353 			goto doseek;
   1354 		}
   1355 		fdfinish(fd, bp);
   1356 		goto loop;
   1357 
   1358 	case COPYCOMPLETE: /* IO DONE, post-analyze */
   1359 		DPRINTF(("fdcintr: COPYCOMPLETE:"));
   1360 		callout_stop(&fdc->sc_timo_ch);
   1361 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
   1362 			printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
   1363 #if 0
   1364 			isa_dmaabort(fdc->sc_drq);
   1365 #endif
   1366 			fdcstatus(fd->sc_dev, 7, bp->b_flags & B_READ ?
   1367 				  "read failed" : "write failed");
   1368 			printf("blkno %" PRId64 " nblks %d\n",
   1369 			    fd->sc_blkno, fd->sc_nblks);
   1370 			fdcretry(fdc);
   1371 			goto loop;
   1372 		}
   1373 		goto doiohalf;
   1374 
   1375 	case DORESET:
   1376 		DPRINTF(("fdcintr: in DORESET\n"));
   1377 		/* try a reset, keep motor on */
   1378 		fd_set_motor(fdc, 1);
   1379 		DELAY(100);
   1380 		fd_set_motor(fdc, 0);
   1381 		fdc->sc_state = RESETCOMPLETE;
   1382 		callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
   1383 		return 1;			/* will return later */
   1384 
   1385 	case RESETCOMPLETE:
   1386 		DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
   1387 		callout_stop(&fdc->sc_timo_ch);
   1388 		/* clear the controller output buffer */
   1389 		for (i = 0; i < 4; i++) {
   1390 			out_fdc(iot, ioh, NE7CMD_SENSEI);
   1391 			(void) fdcresult(fdc);
   1392 		}
   1393 
   1394 		/* fall through */
   1395 	case DORECAL:
   1396 		DPRINTF(("fdcintr: in DORECAL\n"));
   1397 		out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
   1398 		out_fdc(iot, ioh, fd->sc_drive);
   1399 		fdc->sc_state = RECALWAIT;
   1400 		callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
   1401 		return 1;			/* will return later */
   1402 
   1403 	case RECALWAIT:
   1404 		DPRINTF(("fdcintr: in RECALWAIT\n"));
   1405 		callout_stop(&fdc->sc_timo_ch);
   1406 		fdc->sc_state = RECALCOMPLETE;
   1407 		/* allow 1/30 second for heads to settle */
   1408 #if 0
   1409 		callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
   1410 #endif
   1411 		return 1;			/* will return later */
   1412 
   1413 	case RECALCOMPLETE:
   1414 		DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
   1415 		out_fdc(iot, ioh, NE7CMD_SENSEI);
   1416 		tmp = fdcresult(fdc);
   1417 		if ((st0 & 0xf8) == 0xc0) {
   1418 			DPRINTF(("fdcintr: first seek!\n"));
   1419 			fdc->sc_state = DORECAL;
   1420 			goto loop;
   1421 		} else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
   1422 #ifdef FDDEBUG
   1423 			fdcstatus(fd->sc_dev, 2, "recalibrate failed");
   1424 #endif
   1425 			fdcretry(fdc);
   1426 			goto loop;
   1427 		}
   1428 		fd->sc_cylin = 0;
   1429 		goto doseek;
   1430 
   1431 	case MOTORWAIT:
   1432 		if (fd->sc_flags & FD_MOTOR_WAIT)
   1433 			return 1;		/* time's not up yet */
   1434 		goto doseek;
   1435 
   1436 	default:
   1437 		fdcstatus(fd->sc_dev, 0, "stray interrupt");
   1438 		return 1;
   1439 	}
   1440 #ifdef DIAGNOSTIC
   1441 	panic("fdcintr: impossible");
   1442 #endif
   1443 #undef	st0
   1444 #undef	cyl
   1445 }
   1446 
   1447 void
   1448 fdcretry(struct fdc_softc *fdc)
   1449 {
   1450 	struct fd_softc *fd;
   1451 	struct buf *bp;
   1452 	char bits[64];
   1453 
   1454 	DPRINTF(("fdcretry:\n"));
   1455 	fd = fdc->sc_drives.tqh_first;
   1456 	bp = BUFQ_PEEK(fd->sc_q);
   1457 
   1458 	switch (fdc->sc_errors) {
   1459 	case 0:
   1460 		/* try again */
   1461 		fdc->sc_state = SEEKCOMPLETE;
   1462 		break;
   1463 
   1464 	case 1: case 2: case 3:
   1465 		/* didn't work; try recalibrating */
   1466 		fdc->sc_state = DORECAL;
   1467 		break;
   1468 
   1469 	case 4:
   1470 		/* still no go; reset the bastard */
   1471 		fdc->sc_state = DORESET;
   1472 		break;
   1473 
   1474 	default:
   1475 		diskerr(bp, "fd", "hard error", LOG_PRINTF,
   1476 			fd->sc_skip, (struct disklabel *)NULL);
   1477 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
   1478 						    NE7_ST0BITS, bits,
   1479 						    sizeof(bits)));
   1480 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
   1481 						   NE7_ST1BITS, bits,
   1482 						   sizeof(bits)));
   1483 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
   1484 						   NE7_ST2BITS, bits,
   1485 						   sizeof(bits)));
   1486 		printf(" cyl %d head %d sec %d)\n",
   1487 		       fdc->sc_status[3],
   1488 		       fdc->sc_status[4],
   1489 		       fdc->sc_status[5]);
   1490 
   1491 		bp->b_error = EIO;
   1492 		fdfinish(fd, bp);
   1493 	}
   1494 	fdc->sc_errors++;
   1495 }
   1496 
   1497 int
   1498 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
   1499 {
   1500 	struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
   1501 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
   1502 	int part = DISKPART(dev);
   1503 	struct disklabel buffer;
   1504 	int error;
   1505 
   1506 	DPRINTF(("fdioctl:\n"));
   1507 	switch (cmd) {
   1508 	case DIOCGDINFO:
   1509 #if 1
   1510 		*(struct disklabel *)addr = *(fd->sc_dk.dk_label);
   1511 		return(0);
   1512 #else
   1513 		memset(&buffer, 0, sizeof(buffer));
   1514 
   1515 		buffer.d_secpercyl = fd->sc_type->seccyl;
   1516 		buffer.d_type = DTYPE_FLOPPY;
   1517 		buffer.d_secsize = 128 << fd->sc_type->secsize;
   1518 
   1519 		if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
   1520 			return EINVAL;
   1521 
   1522 		*(struct disklabel *)addr = buffer;
   1523 		return 0;
   1524 #endif
   1525 
   1526 	case DIOCGPART:
   1527 		((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
   1528 		((struct partinfo *)addr)->part =
   1529 		    &fd->sc_dk.dk_label->d_partitions[part];
   1530 		return(0);
   1531 
   1532 	case DIOCWLABEL:
   1533 		if ((flag & FWRITE) == 0)
   1534 			return EBADF;
   1535 		/* XXX do something */
   1536 		return 0;
   1537 
   1538 	case DIOCWDINFO:
   1539 		if ((flag & FWRITE) == 0)
   1540 			return EBADF;
   1541 
   1542 		error = setdisklabel(&buffer, (struct disklabel *)addr,
   1543 		                     0, NULL);
   1544 		if (error)
   1545 			return error;
   1546 
   1547 		error = writedisklabel(dev, fdstrategy, &buffer, NULL);
   1548 		return error;
   1549 
   1550 	case DIOCLOCK:
   1551 		/*
   1552 		 * Nothing to do here, really.
   1553 		 */
   1554 		return 0; /* XXX */
   1555 
   1556 	case DIOCEJECT:
   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 		fd_do_eject(fdc, FDUNIT(dev));
   1571 		return 0;
   1572 
   1573 	default:
   1574 		return ENOTTY;
   1575 	}
   1576 
   1577 #ifdef DIAGNOSTIC
   1578 	panic("fdioctl: impossible");
   1579 #endif
   1580 }
   1581 
   1582 void
   1583 fd_do_eject(struct fdc_softc *fdc, int unit)
   1584 {
   1585 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
   1586 			  0x20 | ( 1 << unit));
   1587 	DELAY(1); /* XXX */
   1588 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20);
   1589 }
   1590 
   1591 /*
   1592  * Build disk label. For now we only create a label from what we know
   1593  * from 'sc'.
   1594  */
   1595 static int
   1596 fdgetdisklabel(struct fd_softc *sc, dev_t dev)
   1597 {
   1598 	struct disklabel *lp;
   1599 	int part;
   1600 
   1601 	DPRINTF(("fdgetdisklabel()\n"));
   1602 
   1603 	part = DISKPART(dev);
   1604 	lp = sc->sc_dk.dk_label;
   1605 	memset(lp, 0, sizeof(struct disklabel));
   1606 
   1607 	lp->d_secsize     = 128 << sc->sc_type->secsize;
   1608 	lp->d_ntracks     = sc->sc_type->heads;
   1609 	lp->d_nsectors    = sc->sc_type->sectrac;
   1610 	lp->d_secpercyl   = lp->d_ntracks * lp->d_nsectors;
   1611 	lp->d_ncylinders  = sc->sc_type->size / lp->d_secpercyl;
   1612 	lp->d_secperunit  = sc->sc_type->size;
   1613 
   1614 	lp->d_type        = DTYPE_FLOPPY;
   1615 	lp->d_rpm         = 300; 	/* XXX */
   1616 	lp->d_interleave  = 1;		/* FIXME: is this OK?		*/
   1617 	lp->d_bbsize      = 0;
   1618 	lp->d_sbsize      = 0;
   1619 	lp->d_npartitions = part + 1;
   1620 #define STEP_DELAY	6000	/* 6ms (6000us) delay after stepping	*/
   1621 	lp->d_trkseek     = STEP_DELAY; /* XXX */
   1622 	lp->d_magic       = DISKMAGIC;
   1623 	lp->d_magic2      = DISKMAGIC;
   1624 	lp->d_checksum    = dkcksum(lp);
   1625 	lp->d_partitions[part].p_size   = lp->d_secperunit;
   1626 	lp->d_partitions[part].p_fstype = FS_UNUSED;
   1627 	lp->d_partitions[part].p_fsize  = 1024;
   1628 	lp->d_partitions[part].p_frag   = 8;
   1629 
   1630 	return(0);
   1631 }
   1632 
   1633 #include <dev/cons.h>
   1634 
   1635 /*
   1636  * Mountroot hook: prompt the user to enter the root file system
   1637  * floppy.
   1638  */
   1639 void
   1640 fd_mountroot_hook(device_t dev)
   1641 {
   1642 	struct fd_softc *fd = device_private(dev);
   1643 	struct fdc_softc *fdc = device_private(device_parent(fd->sc_dev));
   1644 	int c;
   1645 
   1646 	/* XXX device_unit() abuse */
   1647 	fd_do_eject(fdc, device_unit(dev));
   1648 	printf("Insert filesystem floppy and press return.");
   1649 	for (;;) {
   1650 		c = cngetc();
   1651 		if ((c == '\r') || (c == '\n')) {
   1652 			printf("\n");
   1653 			break;
   1654 		}
   1655 	}
   1656 }
   1657