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