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