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