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