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