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