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