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