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