Home | History | Annotate | Line # | Download | only in dev
fd.c revision 1.82
      1 /*	$NetBSD: fd.c,v 1.82 2008/06/14 13:36:24 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.82 2008/06/14 13:36:24 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 	struct device 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(struct device *, struct cfdata *, void *);
    167 void fdcattach(struct device *, struct device *, void *);
    168 int fdprint(void *, const char *);
    169 
    170 CFATTACH_DECL(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 	struct device 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(struct device *, struct cfdata *, void *);
    252 void fdattach(struct device *, struct device *, void *);
    253 
    254 CFATTACH_DECL(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(struct device *, 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(struct device *);
    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(struct device *parent, struct cfdata *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(struct device *parent, struct device *self, void *aux)
    405 {
    406 	struct fdc_softc *fdc = (void *)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 	printf("\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 		printf("%s: can't set up intio DMA map\n",
    439 		    fdc->sc_dev.dv_xname);
    440 		return;
    441 	}
    442 
    443 	if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc))
    444 		panic ("Could not establish interrupt (duplicated vector?).");
    445 	intio_set_ivec(ia->ia_intr);
    446 
    447 	/* reset */
    448 	intio_disable_intr(SICILIAN_INTR_FDD);
    449 	intio_enable_intr(SICILIAN_INTR_FDC);
    450 	fdcresult(fdc);
    451 	fdcreset(fdc);
    452 
    453 	printf("%s: uPD72065 FDC\n", fdc->sc_dev.dv_xname);
    454 	out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
    455 	out_fdc(iot, ioh, 0xd0);
    456 	out_fdc(iot, ioh, 0x10);
    457 
    458 	/* physical limit: four drives per controller. */
    459 	for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
    460 		(void)config_found(self, (void *)&fa, fdprint);
    461 	}
    462 
    463 	intio_enable_intr(SICILIAN_INTR_FDC);
    464 }
    465 
    466 void
    467 fdcreset(struct fdc_softc *fdc)
    468 {
    469 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdsts, NE7CMD_RESET);
    470 }
    471 
    472 static int
    473 fdcpoll(struct fdc_softc *fdc)
    474 {
    475 	int i = 25000, n;
    476 	while (--i > 0) {
    477 		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
    478 			out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
    479 			n = fdcresult(fdc);
    480 			break;
    481 		}
    482 		DELAY(100);
    483 	}
    484 	return i;
    485 }
    486 
    487 int
    488 fdprobe(struct device *parent, struct cfdata *cf, void *aux)
    489 {
    490 	struct fdc_softc *fdc = (void *)parent;
    491 	struct fd_type *type;
    492 	struct fdc_attach_args *fa = aux;
    493 	int drive = fa->fa_drive;
    494 	bus_space_tag_t iot = fdc->sc_iot;
    495 	bus_space_handle_t ioh = fdc->sc_ioh;
    496 	int n = 0;
    497 	int found = 0;
    498 	int i;
    499 
    500 	if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
    501 	    cf->cf_loc[FDCCF_UNIT] != drive)
    502 		return 0;
    503 
    504 	type = &fd_types[0];	/* XXX 1.2MB */
    505 
    506 	intio_disable_intr(SICILIAN_INTR_FDC);
    507 
    508 	/* select drive and turn on motor */
    509 	bus_space_write_1(iot, ioh, fdctl, 0x80 | (type->rate << 4)| drive);
    510 	fdc_force_ready(FDCRDY);
    511 	fdcpoll(fdc);
    512 
    513 retry:
    514 	out_fdc(iot, ioh, NE7CMD_RECAL);
    515 	out_fdc(iot, ioh, drive);
    516 
    517 	i = 25000;
    518 	while (--i > 0) {
    519 		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
    520 			out_fdc(iot, ioh, NE7CMD_SENSEI);
    521 			n = fdcresult(fdc);
    522 			break;
    523 		}
    524 		DELAY(100);
    525 	}
    526 
    527 #ifdef FDDEBUG
    528 	{
    529 		int _i;
    530 		DPRINTF(("fdprobe: status"));
    531 		for (_i = 0; _i < n; _i++)
    532 			DPRINTF((" %x", fdc->sc_status[_i]));
    533 		DPRINTF(("\n"));
    534 	}
    535 #endif
    536 
    537 	if (n == 2) {
    538 		if ((fdc->sc_status[0] & 0xf0) == 0x20)
    539 			found = 1;
    540 		else if ((fdc->sc_status[0] & 0xf0) == 0xc0)
    541 			goto retry;
    542 	}
    543 
    544 	/* turn off motor */
    545 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh,
    546 			  fdctl, (type->rate << 4)| drive);
    547 	fdc_force_ready(FDCSTBY);
    548 	if (!found) {
    549 		intio_enable_intr(SICILIAN_INTR_FDC);
    550 		return 0;
    551 	}
    552 
    553 	return 1;
    554 }
    555 
    556 /*
    557  * Controller is working, and drive responded.  Attach it.
    558  */
    559 void
    560 fdattach(struct device *parent, struct device *self, void *aux)
    561 {
    562 	struct fdc_softc *fdc = (void *)parent;
    563 	struct fd_softc *fd = (void *)self;
    564 	struct fdc_attach_args *fa = aux;
    565 	struct fd_type *type = &fd_types[0];	/* XXX 1.2MB */
    566 	int drive = fa->fa_drive;
    567 
    568 	callout_init(&fd->sc_motoron_ch, 0);
    569 	callout_init(&fd->sc_motoroff_ch, 0);
    570 
    571 	fd->sc_flags = 0;
    572 
    573 	if (type)
    574 		printf(": %s, %d cyl, %d head, %d sec\n", type->name,
    575 		       type->cyls, type->heads, type->sectrac);
    576 	else
    577 		printf(": 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 		printf("fdprobe: WARNING!! malloc() failed.\n");
    588 	fd->sc_flags |= FD_ALIVE;
    589 
    590 	/*
    591 	 * Initialize and attach the disk structure.
    592 	 */
    593 	disk_init(&fd->sc_dk, fd->sc_dev.dv_xname, &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, fd->sc_dev.dv_xname,
    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 sz;
    623 	int s;
    624 
    625 	fd = device_lookup_private(&fd_cd, FDUNIT(bp->b_dev));
    626 	if (fd == NULL) {
    627 		bp->b_error = EINVAL;
    628 		goto done;
    629 	}
    630 
    631 	if (bp->b_blkno < 0 ||
    632 	    (bp->b_bcount % FDC_BSIZE) != 0) {
    633 		DPRINTF(("fdstrategy: unit=%d, blkno=%" PRId64 ", "
    634 			 "bcount=%d\n", unit,
    635 			 bp->b_blkno, bp->b_bcount));
    636 		bp->b_error = EINVAL;
    637 		goto done;
    638 	}
    639 
    640 	/* If it's a null transfer, return immediately. */
    641 	if (bp->b_bcount == 0)
    642 		goto done;
    643 
    644 	sz = howmany(bp->b_bcount, FDC_BSIZE);
    645 
    646 	if (bp->b_blkno + sz >
    647 	    (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
    648 		sz = (fd->sc_type->size << (fd->sc_type->secsize - 2))
    649 		     - bp->b_blkno;
    650 		if (sz == 0) {
    651 			/* If exactly at end of disk, return EOF. */
    652 			bp->b_resid = bp->b_bcount;
    653 			goto done;
    654 		}
    655 		if (sz < 0) {
    656 			/* If past end of disk, return EINVAL. */
    657 			bp->b_error = EINVAL;
    658 			goto done;
    659 		}
    660 		/* Otherwise, truncate request. */
    661 		bp->b_bcount = sz << DEV_BSHIFT;
    662 	}
    663 
    664 	bp->b_rawblkno = bp->b_blkno;
    665 	bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)
    666 		/ (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2)));
    667 
    668 	DPRINTF(("fdstrategy: %s b_blkno %" PRId64 " b_bcount %d cylin %d\n",
    669 		 bp->b_flags & B_READ ? "read" : "write",
    670 		 bp->b_blkno, bp->b_bcount, bp->b_cylinder));
    671 	/* Queue transfer on drive, activate drive and controller if idle. */
    672 	s = splbio();
    673 	BUFQ_PUT(fd->sc_q, bp);
    674 	callout_stop(&fd->sc_motoroff_ch);		/* a good idea */
    675 	if (fd->sc_active == 0)
    676 		fdstart(fd);
    677 #ifdef DIAGNOSTIC
    678 	else {
    679 		struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
    680 		if (fdc->sc_state == DEVIDLE) {
    681 			printf("fdstrategy: controller inactive\n");
    682 			fdcstart(fdc);
    683 		}
    684 	}
    685 #endif
    686 	splx(s);
    687 	return;
    688 
    689 done:
    690 	/* Toss transfer; we're done early. */
    691 	biodone(bp);
    692 }
    693 
    694 void
    695 fdstart(struct fd_softc *fd)
    696 {
    697 	struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
    698 	int active = fdc->sc_drives.tqh_first != 0;
    699 
    700 	/* Link into controller queue. */
    701 	fd->sc_active = 1;
    702 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    703 
    704 	/* If controller not already active, start it. */
    705 	if (!active)
    706 		fdcstart(fdc);
    707 }
    708 
    709 void
    710 fdfinish(struct fd_softc *fd, struct buf *bp)
    711 {
    712 	struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
    713 
    714 	/*
    715 	 * Move this drive to the end of the queue to give others a `fair'
    716 	 * chance.  We only force a switch if N operations are completed while
    717 	 * another drive is waiting to be serviced, since there is a long motor
    718 	 * startup delay whenever we switch.
    719 	 */
    720 	(void)BUFQ_GET(fd->sc_q);
    721 	if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
    722 		fd->sc_ops = 0;
    723 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
    724 		if (BUFQ_PEEK(fd->sc_q) != NULL) {
    725 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    726 		} else
    727 			fd->sc_active = 0;
    728 	}
    729 	bp->b_resid = fd->sc_bcount;
    730 	fd->sc_skip = 0;
    731 
    732 #if NRND > 0
    733 	rnd_add_uint32(&fd->rnd_source, bp->b_blkno);
    734 #endif
    735 
    736 	biodone(bp);
    737 	/* turn off motor 5s from now */
    738 	callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
    739 	fdc->sc_state = DEVIDLE;
    740 }
    741 
    742 int
    743 fdread(dev_t dev, struct uio *uio, int flags)
    744 {
    745 
    746 	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
    747 }
    748 
    749 int
    750 fdwrite(dev_t dev, struct uio *uio, int flags)
    751 {
    752 
    753 	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
    754 }
    755 
    756 void
    757 fd_set_motor(struct fdc_softc *fdc, int reset)
    758 {
    759 	struct fd_softc *fd;
    760 	int n;
    761 
    762 	DPRINTF(("fd_set_motor:\n"));
    763 	for (n = 0; n < 4; n++)
    764 		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) {
    765 			bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl,
    766 					  0x80 | (fd->sc_type->rate << 4)| n);
    767 		}
    768 }
    769 
    770 void
    771 fd_motor_off(void *arg)
    772 {
    773 	struct fd_softc *fd = arg;
    774 	struct fdc_softc *fdc = (struct fdc_softc*) device_parent(&fd->sc_dev);
    775 	int s;
    776 
    777 	DPRINTF(("fd_motor_off:\n"));
    778 
    779 	s = splbio();
    780 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
    781 	bus_space_write_1 (fdc->sc_iot, fdc->sc_ioh, fdctl,
    782 			   (fd->sc_type->rate << 4) | fd->sc_drive);
    783 #if 0
    784 	fd_set_motor(fdc, 0); /* XXX */
    785 #endif
    786 	splx(s);
    787 }
    788 
    789 void
    790 fd_motor_on(void *arg)
    791 {
    792 	struct fd_softc *fd = arg;
    793 	struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
    794 	int s;
    795 
    796 	DPRINTF(("fd_motor_on:\n"));
    797 
    798 	s = splbio();
    799 	fd->sc_flags &= ~FD_MOTOR_WAIT;
    800 	if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
    801 		(void) fdcintr(fdc);
    802 	splx(s);
    803 }
    804 
    805 int
    806 fdcresult(struct fdc_softc *fdc)
    807 {
    808 	bus_space_tag_t iot = fdc->sc_iot;
    809 	bus_space_handle_t ioh = fdc->sc_ioh;
    810 	u_char i;
    811 	int j = 100000,
    812 	    n = 0;
    813 
    814 	for (; j; j--) {
    815 		i = bus_space_read_1(iot, ioh, fdsts) &
    816 		  (NE7_DIO | NE7_RQM | NE7_CB);
    817 
    818 		if (i == NE7_RQM)
    819 			return n;
    820 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
    821 			if (n >= sizeof(fdc->sc_status)) {
    822 				log(LOG_ERR, "fdcresult: overrun\n");
    823 				return -1;
    824 			}
    825 			fdc->sc_status[n++] =
    826 			  bus_space_read_1(iot, ioh, fddata);
    827 		}
    828 		delay(10);
    829 	}
    830 	log(LOG_ERR, "fdcresult: timeout\n");
    831 	return -1;
    832 }
    833 
    834 int
    835 out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x)
    836 {
    837 	int i = 100000;
    838 
    839 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
    840 	if (i <= 0)
    841 		return -1;
    842 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
    843 	if (i <= 0)
    844 		return -1;
    845 	bus_space_write_1(iot, ioh, fddata, x);
    846 	return 0;
    847 }
    848 
    849 int
    850 fdopen(dev_t dev, int flags, int mode, struct lwp *l)
    851 {
    852 	int unit;
    853 	struct fd_softc *fd;
    854 	struct fd_type *type;
    855 	struct fdc_softc *fdc;
    856 
    857 	unit = FDUNIT(dev);
    858 	fd = device_lookup_private(&fd_cd, unit);
    859 	if (fd == NULL)
    860 		return ENXIO;
    861 	type = fd_dev_to_type(fd, dev);
    862 	if (type == NULL)
    863 		return ENXIO;
    864 
    865 	if ((fd->sc_flags & FD_OPEN) != 0 &&
    866 	    fd->sc_type != type)
    867 		return EBUSY;
    868 
    869 	fdc = device_private(device_parent(&fd->sc_dev));
    870 	if ((fd->sc_flags & FD_OPEN) == 0) {
    871 		/* Lock eject button */
    872 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
    873 				  0x40 | ( 1 << unit));
    874 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x40);
    875 	}
    876 
    877 	fd->sc_type = type;
    878 	fd->sc_cylin = -1;
    879 
    880 	switch (mode) {
    881 	case S_IFCHR:
    882 		fd->sc_flags |= FD_COPEN;
    883 		break;
    884 	case S_IFBLK:
    885 		fd->sc_flags |= FD_BOPEN;
    886 		break;
    887 	}
    888 
    889 	fdgetdisklabel(fd, dev);
    890 
    891 	return 0;
    892 }
    893 
    894 int
    895 fdclose(dev_t dev, int flags, int mode, struct lwp *l)
    896 {
    897 	int unit = FDUNIT(dev);
    898 	struct fd_softc *fd = device_lookup_private(&fd_cd, unit);
    899 	struct fdc_softc *fdc = device_private(device_parent(&fd->sc_dev));
    900 
    901 	DPRINTF(("fdclose %d\n", unit));
    902 
    903 	switch (mode) {
    904 	case S_IFCHR:
    905 		fd->sc_flags &= ~FD_COPEN;
    906 		break;
    907 	case S_IFBLK:
    908 		fd->sc_flags &= ~FD_BOPEN;
    909 		break;
    910 	}
    911 
    912 	if ((fd->sc_flags & FD_OPEN) == 0) {
    913 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
    914 				  ( 1 << unit));
    915 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0);
    916 	}
    917 	return 0;
    918 }
    919 
    920 void
    921 fdcstart(struct fdc_softc *fdc)
    922 {
    923 
    924 #ifdef DIAGNOSTIC
    925 	/* only got here if controller's drive queue was inactive; should
    926 	   be in idle state */
    927 	if (fdc->sc_state != DEVIDLE) {
    928 		printf("fdcstart: not idle\n");
    929 		return;
    930 	}
    931 #endif
    932 	(void) fdcintr(fdc);
    933 }
    934 
    935 void
    936 fdcstatus(struct device *dv, int n, const char *s)
    937 {
    938 	struct fdc_softc *fdc = (void *)device_parent(dv);
    939 	char bits[64];
    940 
    941 	if (n == 0) {
    942 		out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
    943 		(void) fdcresult(fdc);
    944 		n = 2;
    945 	}
    946 
    947 	printf("%s: %s: state %d", dv->dv_xname, s, fdc->sc_state);
    948 
    949 	switch (n) {
    950 	case 0:
    951 		printf("\n");
    952 		break;
    953 	case 2:
    954 		printf(" (st0 %s cyl %d)\n",
    955 		    bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
    956 		    bits, sizeof(bits)), fdc->sc_status[1]);
    957 		break;
    958 	case 7:
    959 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
    960 		    NE7_ST0BITS, bits, sizeof(bits)));
    961 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
    962 		    NE7_ST1BITS, bits, sizeof(bits)));
    963 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
    964 		    NE7_ST2BITS, bits, sizeof(bits)));
    965 		printf(" cyl %d head %d sec %d)\n",
    966 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
    967 		break;
    968 #ifdef DIAGNOSTIC
    969 	default:
    970 		printf(" fdcstatus: weird size: %d\n", n);
    971 		break;
    972 #endif
    973 	}
    974 }
    975 
    976 void
    977 fdctimeout(void *arg)
    978 {
    979 	struct fdc_softc *fdc = arg;
    980 	struct fd_softc *fd = fdc->sc_drives.tqh_first;
    981 	int s;
    982 
    983 	s = splbio();
    984 	fdcstatus(&fd->sc_dev, 0, "timeout");
    985 
    986 	if (BUFQ_PEEK(fd->sc_q) != NULL)
    987 		fdc->sc_state++;
    988 	else
    989 		fdc->sc_state = DEVIDLE;
    990 
    991 	(void) fdcintr(fdc);
    992 	splx(s);
    993 }
    994 
    995 #if 0
    996 void
    997 fdcpseudointr(void *arg)
    998 {
    999 	int s;
   1000 	struct fdc_softc *fdc = arg;
   1001 
   1002 	/* just ensure it has the right spl */
   1003 	s = splbio();
   1004 	(void) fdcintr(fdc);
   1005 	splx(s);
   1006 }
   1007 #endif
   1008 
   1009 int
   1010 fdcintr(void *arg)
   1011 {
   1012 	struct fdc_softc *fdc = arg;
   1013 #define	st0	fdc->sc_status[0]
   1014 #define	cyl	fdc->sc_status[1]
   1015 	struct fd_softc *fd;
   1016 	struct buf *bp;
   1017 	bus_space_tag_t iot = fdc->sc_iot;
   1018 	bus_space_handle_t ioh = fdc->sc_ioh;
   1019 	int read, head, sec, pos, i, sectrac, nblks;
   1020 	int	tmp;
   1021 	struct fd_type *type;
   1022 
   1023 loop:
   1024 	fd = fdc->sc_drives.tqh_first;
   1025 	if (fd == NULL) {
   1026 		DPRINTF(("fdcintr: set DEVIDLE\n"));
   1027 		if (fdc->sc_state == DEVIDLE) {
   1028 			if (intio_get_sicilian_intr() & SICILIAN_STAT_FDC) {
   1029 				out_fdc(iot, ioh, NE7CMD_SENSEI);
   1030 				if ((tmp = fdcresult(fdc)) != 2 ||
   1031 				    (st0 & 0xf8) != 0x20) {
   1032 					goto loop;
   1033 				}
   1034 			}
   1035 		}
   1036 		/* no drives waiting; end */
   1037 		fdc->sc_state = DEVIDLE;
   1038 		return 1;
   1039 	}
   1040 
   1041 	/* Is there a transfer to this drive?  If not, deactivate drive. */
   1042 	bp = BUFQ_PEEK(fd->sc_q);
   1043 	if (bp == NULL) {
   1044 		fd->sc_ops = 0;
   1045 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
   1046 		fd->sc_active = 0;
   1047 		goto loop;
   1048 	}
   1049 
   1050 	switch (fdc->sc_state) {
   1051 	case DEVIDLE:
   1052 		DPRINTF(("fdcintr: in DEVIDLE\n"));
   1053 		fdc->sc_errors = 0;
   1054 		fd->sc_skip = 0;
   1055 		fd->sc_bcount = bp->b_bcount;
   1056 		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
   1057 		callout_stop(&fd->sc_motoroff_ch);
   1058 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
   1059 			fdc->sc_state = MOTORWAIT;
   1060 			return 1;
   1061 		}
   1062 		if ((fd->sc_flags & FD_MOTOR) == 0) {
   1063 			/* Turn on the motor */
   1064 			/* being careful about other drives. */
   1065 			for (i = 0; i < 4; i++) {
   1066 				struct fd_softc *ofd = fdc->sc_fd[i];
   1067 				if (ofd && ofd->sc_flags & FD_MOTOR) {
   1068 					callout_stop(&ofd->sc_motoroff_ch);
   1069 					ofd->sc_flags &=
   1070 						~(FD_MOTOR | FD_MOTOR_WAIT);
   1071 					break;
   1072 				}
   1073 			}
   1074 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
   1075 			fd_set_motor(fdc, 0);
   1076 			fdc->sc_state = MOTORWAIT;
   1077 			/* allow .5s for motor to stabilize */
   1078 			callout_reset(&fd->sc_motoron_ch, hz / 2,
   1079 			    fd_motor_on, fd);
   1080 			return 1;
   1081 		}
   1082 		/* Make sure the right drive is selected. */
   1083 		fd_set_motor(fdc, 0);
   1084 
   1085 		/* fall through */
   1086 	case DOSEEK:
   1087 	doseek:
   1088 		DPRINTF(("fdcintr: in DOSEEK\n"));
   1089 		if (fd->sc_cylin == bp->b_cylinder)
   1090 			goto doio;
   1091 
   1092 		out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
   1093 		out_fdc(iot, ioh, 0xd0);	/* XXX const */
   1094 		out_fdc(iot, ioh, 0x10);
   1095 
   1096 		out_fdc(iot, ioh, NE7CMD_SEEK);	/* seek function */
   1097 		out_fdc(iot, ioh, fd->sc_drive);	/* drive number */
   1098 		out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
   1099 
   1100 		fd->sc_cylin = -1;
   1101 		fdc->sc_state = SEEKWAIT;
   1102 
   1103 		iostat_seek(fd->sc_dk.dk_stats);
   1104 		disk_busy(&fd->sc_dk);
   1105 
   1106 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
   1107 		return 1;
   1108 
   1109 	case DOIO:
   1110 	doio:
   1111 		DPRINTF(("fdcintr: DOIO: "));
   1112 		type = fd->sc_type;
   1113 		sectrac = type->sectrac;
   1114 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
   1115 		sec = pos / (1 << (type->secsize - 2));
   1116 		if (type->secsize == 2) {
   1117 			fd->sc_part = SEC_P11;
   1118 			nblks = (sectrac - sec) << (type->secsize - 2);
   1119 			nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
   1120 			DPRINTF(("nblks(0)"));
   1121 		} else if ((fd->sc_blkno % 2) == 0) {
   1122 			if (fd->sc_bcount & 0x00000200) {
   1123 				if (fd->sc_bcount == FDC_BSIZE) {
   1124 					fd->sc_part = SEC_P10;
   1125 					nblks = 1;
   1126 					DPRINTF(("nblks(1)"));
   1127 				} else {
   1128 					fd->sc_part = SEC_P11;
   1129 					nblks = (sectrac - sec) * 2;
   1130 					nblks = min(nblks, fd->sc_bcount
   1131 						    / FDC_BSIZE - 1);
   1132 					DPRINTF(("nblks(2)"));
   1133 				}
   1134 			} else {
   1135 				fd->sc_part = SEC_P11;
   1136 				nblks = (sectrac - sec)
   1137 					<< (type->secsize - 2);
   1138 				nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
   1139 				DPRINTF(("nblks(3)"));
   1140 			}
   1141 		} else {
   1142 			fd->sc_part = SEC_P01;
   1143 			nblks = 1;
   1144 			DPRINTF(("nblks(4)"));
   1145 		}
   1146 		nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
   1147 		DPRINTF((" %d\n", nblks));
   1148 		fd->sc_nblks = nblks;
   1149 		fd->sc_nbytes = nblks * FDC_BSIZE;
   1150 		head = (fd->sc_blkno
   1151 			% (type->seccyl * (1 << (type->secsize - 2))))
   1152 			 / (type->sectrac * (1 << (type->secsize - 2)));
   1153 
   1154 #ifdef DIAGNOSTIC
   1155 		{int block;
   1156 		 block = ((fd->sc_cylin * type->heads + head) * type->sectrac
   1157 			  + sec) * (1 << (type->secsize - 2));
   1158 		 block += (fd->sc_part == SEC_P01) ? 1 : 0;
   1159 		 if (block != fd->sc_blkno) {
   1160 			 printf("C H R N: %d %d %d %d\n",
   1161 				fd->sc_cylin, head, sec, type->secsize);
   1162 			 printf("fdcintr: doio: block %d != blkno %" PRId64 "\n",
   1163 				block, fd->sc_blkno);
   1164 #ifdef DDB
   1165 			 Debugger();
   1166 #endif
   1167 		 }
   1168 		}
   1169 #endif
   1170 		read = bp->b_flags & B_READ;
   1171 		DPRINTF(("fdcintr: %s drive %d track %d "
   1172 		         "head %d sec %d nblks %d, skip %d\n",
   1173 			 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
   1174 			 head, sec, nblks, fd->sc_skip));
   1175 		DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
   1176 			 type->secsize));
   1177 
   1178 		if (fd->sc_part != SEC_P11)
   1179 			goto docopy;
   1180 
   1181 		fdc_dmastart(fdc, read, (char *)bp->b_data + fd->sc_skip,
   1182 			     fd->sc_nbytes);
   1183 		if (read)
   1184 			out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
   1185 		else
   1186 			out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
   1187 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1188 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
   1189 		out_fdc(iot, ioh, head);
   1190 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
   1191 		out_fdc(iot, ioh, type->secsize);	/* sector size */
   1192 		out_fdc(iot, ioh, type->sectrac);	/* sectors/track */
   1193 		out_fdc(iot, ioh, type->gap1);		/* gap1 size */
   1194 		out_fdc(iot, ioh, type->datalen);	/* data length */
   1195 		fdc->sc_state = IOCOMPLETE;
   1196 
   1197 		disk_busy(&fd->sc_dk);
   1198 
   1199 		/* allow 2 seconds for operation */
   1200 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1201 		return 1;				/* will return later */
   1202 
   1203 	case DOCOPY:
   1204 	docopy:
   1205 		DPRINTF(("fdcintr: DOCOPY:\n"));
   1206 		type = fd->sc_type;
   1207 		head = (fd->sc_blkno
   1208 			% (type->seccyl * (1 << (type->secsize - 2))))
   1209 			 / (type->sectrac * (1 << (type->secsize - 2)));
   1210 		pos = fd->sc_blkno % (type->sectrac * (1 << (type->secsize - 2)));
   1211 		sec = pos / (1 << (type->secsize - 2));
   1212 		fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024);
   1213 		out_fdc(iot, ioh, NE7CMD_READ);		/* READ */
   1214 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1215 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
   1216 		out_fdc(iot, ioh, head);
   1217 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
   1218 		out_fdc(iot, ioh, type->secsize);	/* sector size */
   1219 		out_fdc(iot, ioh, type->sectrac);	/* sectors/track */
   1220 		out_fdc(iot, ioh, type->gap1);		/* gap1 size */
   1221 		out_fdc(iot, ioh, type->datalen);	/* data length */
   1222 		fdc->sc_state = COPYCOMPLETE;
   1223 		/* allow 2 seconds for operation */
   1224 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1225 		return 1;				/* will return later */
   1226 
   1227 	case DOIOHALF:
   1228 	doiohalf:
   1229 		DPRINTF((" DOIOHALF:\n"));
   1230 
   1231 		type = fd->sc_type;
   1232 		sectrac = type->sectrac;
   1233 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
   1234 		sec = pos / (1 << (type->secsize - 2));
   1235 		head = (fd->sc_blkno
   1236 			% (type->seccyl * (1 << (type->secsize - 2))))
   1237 			 / (type->sectrac * (1 << (type->secsize - 2)));
   1238 #ifdef DIAGNOSTIC
   1239 		{int block;
   1240 		 block = ((fd->sc_cylin * type->heads + head) *
   1241 			 type->sectrac + sec)
   1242 			 * (1 << (type->secsize - 2));
   1243 		 block += (fd->sc_part == SEC_P01) ? 1 : 0;
   1244 		 if (block != fd->sc_blkno) {
   1245 			 printf("fdcintr: block %d != blkno %" PRId64 "\n",
   1246 				block, fd->sc_blkno);
   1247 #ifdef DDB
   1248 			 Debugger();
   1249 #endif
   1250 		 }
   1251 		}
   1252 #endif
   1253 		if ((read = bp->b_flags & B_READ)) {
   1254 			memcpy((char *)bp->b_data + fd->sc_skip, fd->sc_copybuf
   1255 			    + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
   1256 			    FDC_BSIZE);
   1257 			fdc->sc_state = IOCOMPLETE;
   1258 			goto iocomplete2;
   1259 		} else {
   1260 			memcpy((char *)fd->sc_copybuf
   1261 			    + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
   1262 			    (char *)bp->b_data + fd->sc_skip, FDC_BSIZE);
   1263 			fdc_dmastart(fdc, read, fd->sc_copybuf, 1024);
   1264 		}
   1265 		out_fdc(iot, ioh, NE7CMD_WRITE);	/* WRITE */
   1266 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1267 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
   1268 		out_fdc(iot, ioh, head);
   1269 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
   1270 		out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */
   1271 		out_fdc(iot, ioh, sectrac);		/* sectors/track */
   1272 		out_fdc(iot, ioh, fd->sc_type->gap1);	/* gap1 size */
   1273 		out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */
   1274 		fdc->sc_state = IOCOMPLETE;
   1275 		/* allow 2 seconds for operation */
   1276 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1277 		return 1;				/* will return later */
   1278 
   1279 	case SEEKWAIT:
   1280 		callout_stop(&fdc->sc_timo_ch);
   1281 		fdc->sc_state = SEEKCOMPLETE;
   1282 		/* allow 1/50 second for heads to settle */
   1283 #if 0
   1284 		callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
   1285 #endif
   1286 		return 1;
   1287 
   1288 	case SEEKCOMPLETE:
   1289 		/* Make sure seek really happened */
   1290 		DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
   1291 			 bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts)));
   1292 		out_fdc(iot, ioh, NE7CMD_SENSEI);
   1293 		tmp = fdcresult(fdc);
   1294 		if ((st0 & 0xf8) == 0xc0) {
   1295 			DPRINTF(("fdcintr: first seek!\n"));
   1296 			fdc->sc_state = DORECAL;
   1297 			goto loop;
   1298 		} else if (tmp != 2 ||
   1299 			   (st0 & 0xf8) != 0x20 ||
   1300 			   cyl != bp->b_cylinder) {
   1301 #ifdef FDDEBUG
   1302 			fdcstatus(&fd->sc_dev, 2, "seek failed");
   1303 #endif
   1304 			fdcretry(fdc);
   1305 			goto loop;
   1306 		}
   1307 		fd->sc_cylin = bp->b_cylinder;
   1308 		goto doio;
   1309 
   1310 	case IOTIMEDOUT:
   1311 #if 0
   1312 		isa_dmaabort(fdc->sc_drq);
   1313 #endif
   1314 	case SEEKTIMEDOUT:
   1315 	case RECALTIMEDOUT:
   1316 	case RESETTIMEDOUT:
   1317 		fdcretry(fdc);
   1318 		goto loop;
   1319 
   1320 	case IOCOMPLETE: /* IO DONE, post-analyze */
   1321 		callout_stop(&fdc->sc_timo_ch);
   1322 		DPRINTF(("fdcintr: in IOCOMPLETE\n"));
   1323 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
   1324 			printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
   1325 #if 0
   1326 			isa_dmaabort(fdc->sc_drq);
   1327 #endif
   1328 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
   1329 				  "read failed" : "write failed");
   1330 			printf("blkno %" PRId64 " nblks %d\n",
   1331 			    fd->sc_blkno, fd->sc_nblks);
   1332 			fdcretry(fdc);
   1333 			goto loop;
   1334 		}
   1335 #if 0
   1336 		isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
   1337 		    nblks * FDC_BSIZE, fdc->sc_drq);
   1338 #endif
   1339 	iocomplete2:
   1340 		if (fdc->sc_errors) {
   1341 			diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
   1342 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
   1343 			printf("\n");
   1344 			fdc->sc_errors = 0;
   1345 		}
   1346 		fd->sc_blkno += fd->sc_nblks;
   1347 		fd->sc_skip += fd->sc_nbytes;
   1348 		fd->sc_bcount -= fd->sc_nbytes;
   1349 		DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
   1350 		if (fd->sc_bcount > 0) {
   1351 			bp->b_cylinder = fd->sc_blkno
   1352 				/ (fd->sc_type->seccyl
   1353 				   * (1 << (fd->sc_type->secsize - 2)));
   1354 			goto doseek;
   1355 		}
   1356 		fdfinish(fd, bp);
   1357 		goto loop;
   1358 
   1359 	case COPYCOMPLETE: /* IO DONE, post-analyze */
   1360 		DPRINTF(("fdcintr: COPYCOMPLETE:"));
   1361 		callout_stop(&fdc->sc_timo_ch);
   1362 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
   1363 			printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
   1364 #if 0
   1365 			isa_dmaabort(fdc->sc_drq);
   1366 #endif
   1367 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
   1368 				  "read failed" : "write failed");
   1369 			printf("blkno %" PRId64 " nblks %d\n",
   1370 			    fd->sc_blkno, fd->sc_nblks);
   1371 			fdcretry(fdc);
   1372 			goto loop;
   1373 		}
   1374 		goto doiohalf;
   1375 
   1376 	case DORESET:
   1377 		DPRINTF(("fdcintr: in DORESET\n"));
   1378 		/* try a reset, keep motor on */
   1379 		fd_set_motor(fdc, 1);
   1380 		DELAY(100);
   1381 		fd_set_motor(fdc, 0);
   1382 		fdc->sc_state = RESETCOMPLETE;
   1383 		callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
   1384 		return 1;			/* will return later */
   1385 
   1386 	case RESETCOMPLETE:
   1387 		DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
   1388 		callout_stop(&fdc->sc_timo_ch);
   1389 		/* clear the controller output buffer */
   1390 		for (i = 0; i < 4; i++) {
   1391 			out_fdc(iot, ioh, NE7CMD_SENSEI);
   1392 			(void) fdcresult(fdc);
   1393 		}
   1394 
   1395 		/* fall through */
   1396 	case DORECAL:
   1397 		DPRINTF(("fdcintr: in DORECAL\n"));
   1398 		out_fdc(iot, ioh, NE7CMD_RECAL); /* recalibrate function */
   1399 		out_fdc(iot, ioh, fd->sc_drive);
   1400 		fdc->sc_state = RECALWAIT;
   1401 		callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
   1402 		return 1;			/* will return later */
   1403 
   1404 	case RECALWAIT:
   1405 		DPRINTF(("fdcintr: in RECALWAIT\n"));
   1406 		callout_stop(&fdc->sc_timo_ch);
   1407 		fdc->sc_state = RECALCOMPLETE;
   1408 		/* allow 1/30 second for heads to settle */
   1409 #if 0
   1410 		callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
   1411 #endif
   1412 		return 1;			/* will return later */
   1413 
   1414 	case RECALCOMPLETE:
   1415 		DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
   1416 		out_fdc(iot, ioh, NE7CMD_SENSEI);
   1417 		tmp = fdcresult(fdc);
   1418 		if ((st0 & 0xf8) == 0xc0) {
   1419 			DPRINTF(("fdcintr: first seek!\n"));
   1420 			fdc->sc_state = DORECAL;
   1421 			goto loop;
   1422 		} else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
   1423 #ifdef FDDEBUG
   1424 			fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
   1425 #endif
   1426 			fdcretry(fdc);
   1427 			goto loop;
   1428 		}
   1429 		fd->sc_cylin = 0;
   1430 		goto doseek;
   1431 
   1432 	case MOTORWAIT:
   1433 		if (fd->sc_flags & FD_MOTOR_WAIT)
   1434 			return 1;		/* time's not up yet */
   1435 		goto doseek;
   1436 
   1437 	default:
   1438 		fdcstatus(&fd->sc_dev, 0, "stray interrupt");
   1439 		return 1;
   1440 	}
   1441 #ifdef DIAGNOSTIC
   1442 	panic("fdcintr: impossible");
   1443 #endif
   1444 #undef	st0
   1445 #undef	cyl
   1446 }
   1447 
   1448 void
   1449 fdcretry(struct fdc_softc *fdc)
   1450 {
   1451 	struct fd_softc *fd;
   1452 	struct buf *bp;
   1453 	char bits[64];
   1454 
   1455 	DPRINTF(("fdcretry:\n"));
   1456 	fd = fdc->sc_drives.tqh_first;
   1457 	bp = BUFQ_PEEK(fd->sc_q);
   1458 
   1459 	switch (fdc->sc_errors) {
   1460 	case 0:
   1461 		/* try again */
   1462 		fdc->sc_state = SEEKCOMPLETE;
   1463 		break;
   1464 
   1465 	case 1: case 2: case 3:
   1466 		/* didn't work; try recalibrating */
   1467 		fdc->sc_state = DORECAL;
   1468 		break;
   1469 
   1470 	case 4:
   1471 		/* still no go; reset the bastard */
   1472 		fdc->sc_state = DORESET;
   1473 		break;
   1474 
   1475 	default:
   1476 		diskerr(bp, "fd", "hard error", LOG_PRINTF,
   1477 			fd->sc_skip, (struct disklabel *)NULL);
   1478 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
   1479 						    NE7_ST0BITS, bits,
   1480 						    sizeof(bits)));
   1481 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
   1482 						   NE7_ST1BITS, bits,
   1483 						   sizeof(bits)));
   1484 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
   1485 						   NE7_ST2BITS, bits,
   1486 						   sizeof(bits)));
   1487 		printf(" cyl %d head %d sec %d)\n",
   1488 		       fdc->sc_status[3],
   1489 		       fdc->sc_status[4],
   1490 		       fdc->sc_status[5]);
   1491 
   1492 		bp->b_error = EIO;
   1493 		fdfinish(fd, bp);
   1494 	}
   1495 	fdc->sc_errors++;
   1496 }
   1497 
   1498 int
   1499 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
   1500 {
   1501 	struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
   1502 	struct fdc_softc *fdc = device_private(device_parent(&fd->sc_dev));
   1503 	int part = DISKPART(dev);
   1504 	struct disklabel buffer;
   1505 	int error;
   1506 
   1507 	DPRINTF(("fdioctl:\n"));
   1508 	switch (cmd) {
   1509 	case DIOCGDINFO:
   1510 #if 1
   1511 		*(struct disklabel *)addr = *(fd->sc_dk.dk_label);
   1512 		return(0);
   1513 #else
   1514 		memset(&buffer, 0, sizeof(buffer));
   1515 
   1516 		buffer.d_secpercyl = fd->sc_type->seccyl;
   1517 		buffer.d_type = DTYPE_FLOPPY;
   1518 		buffer.d_secsize = 128 << fd->sc_type->secsize;
   1519 
   1520 		if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
   1521 			return EINVAL;
   1522 
   1523 		*(struct disklabel *)addr = buffer;
   1524 		return 0;
   1525 #endif
   1526 
   1527 	case DIOCGPART:
   1528 		((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
   1529 		((struct partinfo *)addr)->part =
   1530 		    &fd->sc_dk.dk_label->d_partitions[part];
   1531 		return(0);
   1532 
   1533 	case DIOCWLABEL:
   1534 		if ((flag & FWRITE) == 0)
   1535 			return EBADF;
   1536 		/* XXX do something */
   1537 		return 0;
   1538 
   1539 	case DIOCWDINFO:
   1540 		if ((flag & FWRITE) == 0)
   1541 			return EBADF;
   1542 
   1543 		error = setdisklabel(&buffer, (struct disklabel *)addr,
   1544 		                     0, NULL);
   1545 		if (error)
   1546 			return error;
   1547 
   1548 		error = writedisklabel(dev, fdstrategy, &buffer, NULL);
   1549 		return error;
   1550 
   1551 	case DIOCLOCK:
   1552 		/*
   1553 		 * Nothing to do here, really.
   1554 		 */
   1555 		return 0; /* XXX */
   1556 
   1557 	case DIOCEJECT:
   1558 		if (*(int *)addr == 0) {
   1559 			/*
   1560 			 * Don't force eject: check that we are the only
   1561 			 * partition open. If so, unlock it.
   1562 			 */
   1563 			if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 ||
   1564 			    fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask !=
   1565 			    fd->sc_dk.dk_openmask) {
   1566 				return (EBUSY);
   1567 			}
   1568 		}
   1569 		/* FALLTHROUGH */
   1570 	case ODIOCEJECT:
   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 #include <dev/cons.h>
   1635 
   1636 /*
   1637  * Mountroot hook: prompt the user to enter the root file system
   1638  * floppy.
   1639  */
   1640 void
   1641 fd_mountroot_hook(struct device *dev)
   1642 {
   1643 	struct fd_softc *fd = (void *)dev;
   1644 	struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
   1645 	int c;
   1646 
   1647 	/* XXX device_unit() abuse */
   1648 	fd_do_eject(fdc, device_unit(dev));
   1649 	printf("Insert filesystem floppy and press return.");
   1650 	for (;;) {
   1651 		c = cngetc();
   1652 		if ((c == '\r') || (c == '\n')) {
   1653 			printf("\n");
   1654 			break;
   1655 		}
   1656 	}
   1657 }
   1658