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