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