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