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