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