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