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