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