Home | History | Annotate | Line # | Download | only in dev
fd.c revision 1.81
      1 /*	$NetBSD: fd.c,v 1.81 2008/06/13 13:57:58 cegger 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.81 2008/06/13 13:57:58 cegger 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 unit = FDUNIT(bp->b_dev);
    623 	int sz;
    624 	int s;
    625 
    626 	fd = device_lookup_private(&fd_cd, FDUNIT(bp->b_dev));
    627 	if (fd == NULL) {
    628 		bp->b_error = EINVAL;
    629 		goto done;
    630 	}
    631 
    632 	if (bp->b_blkno < 0 ||
    633 	    (bp->b_bcount % FDC_BSIZE) != 0) {
    634 		DPRINTF(("fdstrategy: unit=%d, blkno=%" PRId64 ", "
    635 			 "bcount=%d\n", unit,
    636 			 bp->b_blkno, bp->b_bcount));
    637 		bp->b_error = EINVAL;
    638 		goto done;
    639 	}
    640 
    641 	/* If it's a null transfer, return immediately. */
    642 	if (bp->b_bcount == 0)
    643 		goto done;
    644 
    645 	sz = howmany(bp->b_bcount, FDC_BSIZE);
    646 
    647 	if (bp->b_blkno + sz >
    648 	    (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
    649 		sz = (fd->sc_type->size << (fd->sc_type->secsize - 2))
    650 		     - bp->b_blkno;
    651 		if (sz == 0) {
    652 			/* If exactly at end of disk, return EOF. */
    653 			bp->b_resid = bp->b_bcount;
    654 			goto done;
    655 		}
    656 		if (sz < 0) {
    657 			/* If past end of disk, return EINVAL. */
    658 			bp->b_error = EINVAL;
    659 			goto done;
    660 		}
    661 		/* Otherwise, truncate request. */
    662 		bp->b_bcount = sz << DEV_BSHIFT;
    663 	}
    664 
    665 	bp->b_rawblkno = bp->b_blkno;
    666 	bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)
    667 		/ (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2)));
    668 
    669 	DPRINTF(("fdstrategy: %s b_blkno %" PRId64 " b_bcount %d cylin %d\n",
    670 		 bp->b_flags & B_READ ? "read" : "write",
    671 		 bp->b_blkno, bp->b_bcount, bp->b_cylinder));
    672 	/* Queue transfer on drive, activate drive and controller if idle. */
    673 	s = splbio();
    674 	BUFQ_PUT(fd->sc_q, bp);
    675 	callout_stop(&fd->sc_motoroff_ch);		/* a good idea */
    676 	if (fd->sc_active == 0)
    677 		fdstart(fd);
    678 #ifdef DIAGNOSTIC
    679 	else {
    680 		struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
    681 		if (fdc->sc_state == DEVIDLE) {
    682 			printf("fdstrategy: controller inactive\n");
    683 			fdcstart(fdc);
    684 		}
    685 	}
    686 #endif
    687 	splx(s);
    688 	return;
    689 
    690 done:
    691 	/* Toss transfer; we're done early. */
    692 	biodone(bp);
    693 }
    694 
    695 void
    696 fdstart(struct fd_softc *fd)
    697 {
    698 	struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
    699 	int active = fdc->sc_drives.tqh_first != 0;
    700 
    701 	/* Link into controller queue. */
    702 	fd->sc_active = 1;
    703 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    704 
    705 	/* If controller not already active, start it. */
    706 	if (!active)
    707 		fdcstart(fdc);
    708 }
    709 
    710 void
    711 fdfinish(struct fd_softc *fd, struct buf *bp)
    712 {
    713 	struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
    714 
    715 	/*
    716 	 * Move this drive to the end of the queue to give others a `fair'
    717 	 * chance.  We only force a switch if N operations are completed while
    718 	 * another drive is waiting to be serviced, since there is a long motor
    719 	 * startup delay whenever we switch.
    720 	 */
    721 	(void)BUFQ_GET(fd->sc_q);
    722 	if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
    723 		fd->sc_ops = 0;
    724 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
    725 		if (BUFQ_PEEK(fd->sc_q) != NULL) {
    726 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    727 		} else
    728 			fd->sc_active = 0;
    729 	}
    730 	bp->b_resid = fd->sc_bcount;
    731 	fd->sc_skip = 0;
    732 
    733 #if NRND > 0
    734 	rnd_add_uint32(&fd->rnd_source, bp->b_blkno);
    735 #endif
    736 
    737 	biodone(bp);
    738 	/* turn off motor 5s from now */
    739 	callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
    740 	fdc->sc_state = DEVIDLE;
    741 }
    742 
    743 int
    744 fdread(dev_t dev, struct uio *uio, int flags)
    745 {
    746 
    747 	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
    748 }
    749 
    750 int
    751 fdwrite(dev_t dev, struct uio *uio, int flags)
    752 {
    753 
    754 	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
    755 }
    756 
    757 void
    758 fd_set_motor(struct fdc_softc *fdc, int reset)
    759 {
    760 	struct fd_softc *fd;
    761 	int n;
    762 
    763 	DPRINTF(("fd_set_motor:\n"));
    764 	for (n = 0; n < 4; n++)
    765 		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) {
    766 			bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl,
    767 					  0x80 | (fd->sc_type->rate << 4)| n);
    768 		}
    769 }
    770 
    771 void
    772 fd_motor_off(void *arg)
    773 {
    774 	struct fd_softc *fd = arg;
    775 	struct fdc_softc *fdc = (struct fdc_softc*) device_parent(&fd->sc_dev);
    776 	int s;
    777 
    778 	DPRINTF(("fd_motor_off:\n"));
    779 
    780 	s = splbio();
    781 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
    782 	bus_space_write_1 (fdc->sc_iot, fdc->sc_ioh, fdctl,
    783 			   (fd->sc_type->rate << 4) | fd->sc_drive);
    784 #if 0
    785 	fd_set_motor(fdc, 0); /* XXX */
    786 #endif
    787 	splx(s);
    788 }
    789 
    790 void
    791 fd_motor_on(void *arg)
    792 {
    793 	struct fd_softc *fd = arg;
    794 	struct fdc_softc *fdc = (void *)device_parent(&fd->sc_dev);
    795 	int s;
    796 
    797 	DPRINTF(("fd_motor_on:\n"));
    798 
    799 	s = splbio();
    800 	fd->sc_flags &= ~FD_MOTOR_WAIT;
    801 	if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
    802 		(void) fdcintr(fdc);
    803 	splx(s);
    804 }
    805 
    806 int
    807 fdcresult(struct fdc_softc *fdc)
    808 {
    809 	bus_space_tag_t iot = fdc->sc_iot;
    810 	bus_space_handle_t ioh = fdc->sc_ioh;
    811 	u_char i;
    812 	int j = 100000,
    813 	    n = 0;
    814 
    815 	for (; j; j--) {
    816 		i = bus_space_read_1(iot, ioh, fdsts) &
    817 		  (NE7_DIO | NE7_RQM | NE7_CB);
    818 
    819 		if (i == NE7_RQM)
    820 			return n;
    821 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
    822 			if (n >= sizeof(fdc->sc_status)) {
    823 				log(LOG_ERR, "fdcresult: overrun\n");
    824 				return -1;
    825 			}
    826 			fdc->sc_status[n++] =
    827 			  bus_space_read_1(iot, ioh, fddata);
    828 		}
    829 		delay(10);
    830 	}
    831 	log(LOG_ERR, "fdcresult: timeout\n");
    832 	return -1;
    833 }
    834 
    835 int
    836 out_fdc(bus_space_tag_t iot, bus_space_handle_t ioh, u_char x)
    837 {
    838 	int i = 100000;
    839 
    840 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
    841 	if (i <= 0)
    842 		return -1;
    843 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
    844 	if (i <= 0)
    845 		return -1;
    846 	bus_space_write_1(iot, ioh, fddata, x);
    847 	return 0;
    848 }
    849 
    850 int
    851 fdopen(dev_t dev, int flags, int mode, struct lwp *l)
    852 {
    853 	struct fd_softc *fd;
    854 	struct fd_type *type;
    855 	struct fdc_softc *fdc;
    856 
    857 	fd = device_lookup_private(&fd_cd, FDUNIT(dev));;
    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(struct device *dv, int n, const char *s)
    936 {
    937 	struct fdc_softc *fdc = (void *)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", dv->dv_xname, 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(struct device *dev)
   1641 {
   1642 	struct fd_softc *fd = (void *)dev;
   1643 	struct fdc_softc *fdc = (void *)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