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