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