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