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