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