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