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