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