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