Home | History | Annotate | Line # | Download | only in dev
fd.c revision 1.29
      1 /*	$NetBSD: fd.c,v 1.29 2000/01/21 23:39:57 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_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)
    674 		/ (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2)));
    675 
    676 	DPRINTF(("fdstrategy: %s b_blkno %d b_bcount %ld cylin %ld\n",
    677 		 bp->b_flags & B_READ ? "read" : "write",
    678 		 bp->b_blkno, bp->b_bcount, bp->b_cylinder));
    679 	/* Queue transfer on drive, activate drive and controller if idle. */
    680 	s = splbio();
    681 	disksort_cylinder(&fd->sc_q, bp);
    682 	untimeout(fd_motor_off, fd); /* a good idea */
    683 	if (fd->sc_active == 0)
    684 		fdstart(fd);
    685 #ifdef DIAGNOSTIC
    686 	else {
    687 		struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    688 		if (fdc->sc_state == DEVIDLE) {
    689 			printf("fdstrategy: controller inactive\n");
    690 			fdcstart(fdc);
    691 		}
    692 	}
    693 #endif
    694 	splx(s);
    695 	return;
    696 
    697 bad:
    698 	bp->b_flags |= B_ERROR;
    699 done:
    700 	/* Toss transfer; we're done early. */
    701 	biodone(bp);
    702 }
    703 
    704 void
    705 fdstart(fd)
    706 	struct fd_softc *fd;
    707 {
    708 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    709 	int active = fdc->sc_drives.tqh_first != 0;
    710 
    711 	/* Link into controller queue. */
    712 	fd->sc_active = 1;
    713 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    714 
    715 	/* If controller not already active, start it. */
    716 	if (!active)
    717 		fdcstart(fdc);
    718 }
    719 
    720 void
    721 fdfinish(fd, bp)
    722 	struct fd_softc *fd;
    723 	struct buf *bp;
    724 {
    725 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    726 
    727 	/*
    728 	 * Move this drive to the end of the queue to give others a `fair'
    729 	 * chance.  We only force a switch if N operations are completed while
    730 	 * another drive is waiting to be serviced, since there is a long motor
    731 	 * startup delay whenever we switch.
    732 	 */
    733 	if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
    734 		fd->sc_ops = 0;
    735 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
    736 		if (BUFQ_NEXT(bp) != NULL) {
    737 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    738 		} else
    739 			fd->sc_active = 0;
    740 	}
    741 	bp->b_resid = fd->sc_bcount;
    742 	fd->sc_skip = 0;
    743 	BUFQ_REMOVE(&fd->sc_q, bp);
    744 
    745 #if NRND > 0
    746 	rnd_add_uint32(&fd->rnd_source, bp->b_blkno);
    747 #endif
    748 
    749 	biodone(bp);
    750 	/* turn off motor 5s from now */
    751 	timeout(fd_motor_off, fd, 5 * hz);
    752 	fdc->sc_state = DEVIDLE;
    753 }
    754 
    755 int
    756 fdread(dev, uio, flags)
    757 	dev_t dev;
    758 	struct uio *uio;
    759 	int flags;
    760 {
    761 
    762 	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
    763 }
    764 
    765 int
    766 fdwrite(dev, uio, flags)
    767 	dev_t dev;
    768 	struct uio *uio;
    769 	int flags;
    770 {
    771 
    772 	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
    773 }
    774 
    775 void
    776 fd_set_motor(fdc, reset)
    777 	struct fdc_softc *fdc;
    778 	int reset;
    779 {
    780 	struct fd_softc *fd;
    781 	int n;
    782 
    783 	DPRINTF(("fd_set_motor:\n"));
    784 	for (n = 0; n < 4; n++)
    785 		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) {
    786 			bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl,
    787 					  0x80 | (fd->sc_type->rate << 4)| n);
    788 		}
    789 }
    790 
    791 void
    792 fd_motor_off(arg)
    793 	void *arg;
    794 {
    795 	struct fd_softc *fd = arg;
    796 	struct fdc_softc *fdc = (struct fdc_softc*) fd->sc_dev.dv_parent;
    797 	int s;
    798 
    799 	DPRINTF(("fd_motor_off:\n"));
    800 
    801 	s = splbio();
    802 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
    803 	bus_space_write_1 (fdc->sc_iot, fdc->sc_ioh, fdctl,
    804 			   (fd->sc_type->rate << 4) | fd->sc_drive);
    805 #if 0
    806 	fd_set_motor(fdc, 0); /* XXX */
    807 #endif
    808 	splx(s);
    809 }
    810 
    811 void
    812 fd_motor_on(arg)
    813 	void *arg;
    814 {
    815 	struct fd_softc *fd = arg;
    816 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    817 	int s;
    818 
    819 	DPRINTF(("fd_motor_on:\n"));
    820 
    821 	s = splbio();
    822 	fd->sc_flags &= ~FD_MOTOR_WAIT;
    823 	if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
    824 		(void) fdcintr(fdc);
    825 	splx(s);
    826 }
    827 
    828 int
    829 fdcresult(fdc)
    830 	struct fdc_softc *fdc;
    831 {
    832 	bus_space_tag_t iot = fdc->sc_iot;
    833 	bus_space_handle_t ioh = fdc->sc_ioh;
    834 	u_char i;
    835 	int j = 100000,
    836 	    n = 0;
    837 
    838 	for (; j; j--) {
    839 		i = bus_space_read_1(iot, ioh, fdsts) &
    840 		  (NE7_DIO | NE7_RQM | NE7_CB);
    841 
    842 		if (i == NE7_RQM)
    843 			return n;
    844 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
    845 			if (n >= sizeof(fdc->sc_status)) {
    846 				log(LOG_ERR, "fdcresult: overrun\n");
    847 				return -1;
    848 			}
    849 			fdc->sc_status[n++] =
    850 			  bus_space_read_1(iot, ioh, fddata);
    851 		}
    852 		delay(10);
    853 	}
    854 	log(LOG_ERR, "fdcresult: timeout\n");
    855 	return -1;
    856 }
    857 
    858 int
    859 out_fdc(iot, ioh, x)
    860 	bus_space_tag_t iot;
    861 	bus_space_handle_t ioh;
    862 	u_char x;
    863 {
    864 	int i = 100000;
    865 
    866 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
    867 	if (i <= 0)
    868 		return -1;
    869 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
    870 	if (i <= 0)
    871 		return -1;
    872 	bus_space_write_1(iot, ioh, fddata, x);
    873 	return 0;
    874 }
    875 
    876 int
    877 fdopen(dev, flags, mode, p)
    878 	dev_t dev;
    879 	int flags, mode;
    880 	struct proc *p;
    881 {
    882  	int unit;
    883 	struct fd_softc *fd;
    884 	struct fd_type *type;
    885 	struct fdc_softc *fdc;
    886 
    887 	unit = FDUNIT(dev);
    888 	if (unit >= fd_cd.cd_ndevs)
    889 		return ENXIO;
    890 	fd = fd_cd.cd_devs[unit];
    891 	if (fd == 0)
    892 		return ENXIO;
    893 	type = fd_dev_to_type(fd, dev);
    894 	if (type == NULL)
    895 		return ENXIO;
    896 
    897 	if ((fd->sc_flags & FD_OPEN) != 0 &&
    898 	    fd->sc_type != type)
    899 		return EBUSY;
    900 
    901 	fdc = (void *)fd->sc_dev.dv_parent;
    902 	if ((fd->sc_flags & FD_OPEN) == 0) {
    903 		/* Lock eject button */
    904 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
    905 				  0x40 | ( 1 << unit));
    906 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x40);
    907 	}
    908 
    909 	fd->sc_type = type;
    910 	fd->sc_cylin = -1;
    911 
    912 	switch (mode) {
    913 	case S_IFCHR:
    914 		fd->sc_flags |= FD_COPEN;
    915 		break;
    916 	case S_IFBLK:
    917 		fd->sc_flags |= FD_BOPEN;
    918 		break;
    919 	}
    920 
    921 	fdgetdisklabel(fd, dev);
    922 
    923 	return 0;
    924 }
    925 
    926 int
    927 fdclose(dev, flags, mode, p)
    928 	dev_t dev;
    929 	int flags, mode;
    930 	struct proc *p;
    931 {
    932  	int unit = FDUNIT(dev);
    933 	struct fd_softc *fd = fd_cd.cd_devs[unit];
    934 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    935 
    936 	DPRINTF(("fdclose %d\n", unit));
    937 
    938 	switch (mode) {
    939 	case S_IFCHR:
    940 		fd->sc_flags &= ~FD_COPEN;
    941 		break;
    942 	case S_IFBLK:
    943 		fd->sc_flags &= ~FD_BOPEN;
    944 		break;
    945 	}
    946 
    947 	if ((fd->sc_flags & FD_OPEN) == 0) {
    948 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
    949 				  ( 1 << unit));
    950 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0);
    951 	}
    952 	return 0;
    953 }
    954 
    955 void
    956 fdcstart(fdc)
    957 	struct fdc_softc *fdc;
    958 {
    959 
    960 #ifdef DIAGNOSTIC
    961 	/* only got here if controller's drive queue was inactive; should
    962 	   be in idle state */
    963 	if (fdc->sc_state != DEVIDLE) {
    964 		printf("fdcstart: not idle\n");
    965 		return;
    966 	}
    967 #endif
    968 	(void) fdcintr(fdc);
    969 }
    970 
    971 void
    972 fdcstatus(dv, n, s)
    973 	struct device *dv;
    974 	int n;
    975 	char *s;
    976 {
    977 	struct fdc_softc *fdc = (void *)dv->dv_parent;
    978 	char bits[64];
    979 
    980 	if (n == 0) {
    981 		out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
    982 		(void) fdcresult(fdc);
    983 		n = 2;
    984 	}
    985 
    986 	printf("%s: %s: state %d", dv->dv_xname, s, fdc->sc_state);
    987 
    988 	switch (n) {
    989 	case 0:
    990 		printf("\n");
    991 		break;
    992 	case 2:
    993 		printf(" (st0 %s cyl %d)\n",
    994 		    bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
    995 		    bits, sizeof(bits)), fdc->sc_status[1]);
    996 		break;
    997 	case 7:
    998 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
    999 		    NE7_ST0BITS, bits, sizeof(bits)));
   1000 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
   1001 		    NE7_ST1BITS, bits, sizeof(bits)));
   1002 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
   1003 		    NE7_ST2BITS, bits, sizeof(bits)));
   1004 		printf(" cyl %d head %d sec %d)\n",
   1005 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
   1006 		break;
   1007 #ifdef DIAGNOSTIC
   1008 	default:
   1009 		printf(" fdcstatus: weird size: %d\n", n);
   1010 		break;
   1011 #endif
   1012 	}
   1013 }
   1014 
   1015 void
   1016 fdctimeout(arg)
   1017 	void *arg;
   1018 {
   1019 	struct fdc_softc *fdc = arg;
   1020 	struct fd_softc *fd = fdc->sc_drives.tqh_first;
   1021 	int s;
   1022 
   1023 	s = splbio();
   1024 	fdcstatus(&fd->sc_dev, 0, "timeout");
   1025 
   1026 	if (BUFQ_FIRST(&fd->sc_q) != NULL)
   1027 		fdc->sc_state++;
   1028 	else
   1029 		fdc->sc_state = DEVIDLE;
   1030 
   1031 	(void) fdcintr(fdc);
   1032 	splx(s);
   1033 }
   1034 
   1035 #if 0
   1036 void
   1037 fdcpseudointr(arg)
   1038 	void *arg;
   1039 {
   1040 	int s;
   1041 	struct fdc_softc *fdc = arg;
   1042 
   1043 	/* just ensure it has the right spl */
   1044 	s = splbio();
   1045 	(void) fdcintr(fdc);
   1046 	splx(s);
   1047 }
   1048 #endif
   1049 
   1050 int
   1051 fdcintr(arg)
   1052 	void *arg;
   1053 {
   1054 	struct fdc_softc *fdc = arg;
   1055 #define	st0	fdc->sc_status[0]
   1056 #define	cyl	fdc->sc_status[1]
   1057 	struct fd_softc *fd;
   1058 	struct buf *bp;
   1059 	bus_space_tag_t iot = fdc->sc_iot;
   1060 	bus_space_handle_t ioh = fdc->sc_ioh;
   1061 	int read, head, sec, pos, i, sectrac, nblks;
   1062 	int	tmp;
   1063 	struct fd_type *type;
   1064 
   1065 loop:
   1066 	fd = fdc->sc_drives.tqh_first;
   1067 	if (fd == NULL) {
   1068 		DPRINTF(("fdcintr: set DEVIDLE\n"));
   1069 		if (fdc->sc_state == DEVIDLE) {
   1070 			if (intio_get_sicilian_intr() & SICILIAN_STAT_FDC) {
   1071 				out_fdc(iot, ioh, NE7CMD_SENSEI);
   1072 				if ((tmp = fdcresult(fdc)) != 2 ||
   1073 				    (st0 & 0xf8) != 0x20) {
   1074 					goto loop;
   1075 				}
   1076 			}
   1077 		}
   1078 		/* no drives waiting; end */
   1079 		fdc->sc_state = DEVIDLE;
   1080  		return 1;
   1081 	}
   1082 
   1083 	/* Is there a transfer to this drive?  If not, deactivate drive. */
   1084 	bp = BUFQ_FIRST(&fd->sc_q);
   1085 	if (bp == NULL) {
   1086 		fd->sc_ops = 0;
   1087 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
   1088 		fd->sc_active = 0;
   1089 		goto loop;
   1090 	}
   1091 
   1092 	switch (fdc->sc_state) {
   1093 	case DEVIDLE:
   1094 		DPRINTF(("fdcintr: in DEVIDLE\n"));
   1095 		fdc->sc_errors = 0;
   1096 		fd->sc_skip = 0;
   1097 		fd->sc_bcount = bp->b_bcount;
   1098 		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
   1099 		untimeout(fd_motor_off, fd);
   1100 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
   1101 			fdc->sc_state = MOTORWAIT;
   1102 			return 1;
   1103 		}
   1104 		if ((fd->sc_flags & FD_MOTOR) == 0) {
   1105 			/* Turn on the motor */
   1106 			/* being careful about other drives. */
   1107 			for (i = 0; i < 4; i++) {
   1108 				struct fd_softc *ofd = fdc->sc_fd[i];
   1109 				if (ofd && ofd->sc_flags & FD_MOTOR) {
   1110 					untimeout(fd_motor_off, ofd);
   1111 					ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
   1112 					break;
   1113 				}
   1114 			}
   1115 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
   1116 			fd_set_motor(fdc, 0);
   1117 			fdc->sc_state = MOTORWAIT;
   1118 			/* allow .5s for motor to stabilize */
   1119 			timeout(fd_motor_on, fd, hz / 2);
   1120 			return 1;
   1121 		}
   1122 		/* Make sure the right drive is selected. */
   1123 		fd_set_motor(fdc, 0);
   1124 
   1125 		/* fall through */
   1126 	case DOSEEK:
   1127 	doseek:
   1128 		DPRINTF(("fdcintr: in DOSEEK\n"));
   1129 		if (fd->sc_cylin == bp->b_cylinder)
   1130 			goto doio;
   1131 
   1132 		out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
   1133 		out_fdc(iot, ioh, 0xd0);	/* XXX const */
   1134 		out_fdc(iot, ioh, 0x10);
   1135 
   1136 		out_fdc(iot, ioh, NE7CMD_SEEK);	/* seek function */
   1137 		out_fdc(iot, ioh, fd->sc_drive);	/* drive number */
   1138 		out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
   1139 
   1140 		fd->sc_cylin = -1;
   1141 		fdc->sc_state = SEEKWAIT;
   1142 
   1143 		fd->sc_dk.dk_seek++;
   1144 		disk_busy(&fd->sc_dk);
   1145 
   1146 		timeout(fdctimeout, fdc, 4 * hz);
   1147 		return 1;
   1148 
   1149 	case DOIO:
   1150 	doio:
   1151 		DPRINTF(("fdcintr: DOIO: "));
   1152 		type = fd->sc_type;
   1153 		sectrac = type->sectrac;
   1154 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
   1155 		sec = pos / (1 << (type->secsize - 2));
   1156 		if (type->secsize == 2) {
   1157 			fd->sc_part = SEC_P11;
   1158 			nblks = (sectrac - sec) << (type->secsize - 2);
   1159 			nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
   1160 			DPRINTF(("nblks(0)"));
   1161 		} else if ((fd->sc_blkno % 2) == 0) {
   1162 			if (fd->sc_bcount & 0x00000200) {
   1163 				if (fd->sc_bcount == FDC_BSIZE) {
   1164 					fd->sc_part = SEC_P10;
   1165 					nblks = 1;
   1166 					DPRINTF(("nblks(1)"));
   1167 				} else {
   1168 					fd->sc_part = SEC_P11;
   1169 					nblks = (sectrac - sec) * 2;
   1170 					nblks = min(nblks, fd->sc_bcount
   1171 						    / FDC_BSIZE - 1);
   1172 					DPRINTF(("nblks(2)"));
   1173 				}
   1174 			} else {
   1175 				fd->sc_part = SEC_P11;
   1176 				nblks = (sectrac - sec)
   1177 					<< (type->secsize - 2);
   1178 				nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
   1179 				DPRINTF(("nblks(3)"));
   1180 			}
   1181 		} else {
   1182 			fd->sc_part = SEC_P01;
   1183 			nblks = 1;
   1184 			DPRINTF(("nblks(4)"));
   1185 		}
   1186 		nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
   1187 		DPRINTF((" %d\n", nblks));
   1188 		fd->sc_nblks = nblks;
   1189 		fd->sc_nbytes = nblks * FDC_BSIZE;
   1190 		head = (fd->sc_blkno
   1191 			% (type->seccyl * (1 << (type->secsize - 2))))
   1192 			 / (type->sectrac * (1 << (type->secsize - 2)));
   1193 
   1194 #ifdef DIAGNOSTIC
   1195 		{int block;
   1196 		 block = ((fd->sc_cylin * type->heads + head) * type->sectrac
   1197 			  + sec) * (1 << (type->secsize - 2));
   1198 		 block += (fd->sc_part == SEC_P01) ? 1 : 0;
   1199 		 if (block != fd->sc_blkno) {
   1200 			 printf("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec, type->secsize);
   1201 			 printf("fdcintr: doio: block %d != blkno %d\n", block, fd->sc_blkno);
   1202 #ifdef DDB
   1203 			 Debugger();
   1204 #endif
   1205 		 }}
   1206 #endif
   1207 		read = bp->b_flags & B_READ;
   1208 		DPRINTF(("fdcintr: %s drive %d track %d head %d sec %d nblks %d, skip %d\n",
   1209 			 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
   1210 			 head, sec, nblks, fd->sc_skip));
   1211 		DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
   1212 			 type->secsize));
   1213 
   1214 		if (fd->sc_part != SEC_P11)
   1215 			goto docopy;
   1216 
   1217 		fdc_dmastart(fdc,
   1218 			     read, bp->b_data + fd->sc_skip, fd->sc_nbytes);
   1219 		if (read)
   1220 			out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
   1221 		else
   1222 			out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
   1223 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1224 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
   1225 		out_fdc(iot, ioh, head);
   1226 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
   1227 		out_fdc(iot, ioh, type->secsize);	/* sector size */
   1228 		out_fdc(iot, ioh, type->sectrac);	/* sectors/track */
   1229 		out_fdc(iot, ioh, type->gap1);		/* gap1 size */
   1230 		out_fdc(iot, ioh, type->datalen);	/* data length */
   1231 		fdc->sc_state = IOCOMPLETE;
   1232 
   1233 		disk_busy(&fd->sc_dk);
   1234 
   1235 		/* allow 2 seconds for operation */
   1236 		timeout(fdctimeout, fdc, 2 * hz);
   1237 		return 1;				/* will return later */
   1238 
   1239 	case DOCOPY:
   1240 	docopy:
   1241 		DPRINTF(("fdcintr: DOCOPY:\n"));
   1242 		fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024);
   1243 		out_fdc(iot, ioh, NE7CMD_READ);		/* READ */
   1244 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1245 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
   1246 		out_fdc(iot, ioh, head);
   1247 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
   1248 		out_fdc(iot, ioh, type->secsize);	/* sector size */
   1249 		out_fdc(iot, ioh, type->sectrac);	/* sectors/track */
   1250 		out_fdc(iot, ioh, type->gap1);		/* gap1 size */
   1251 		out_fdc(iot, ioh, type->datalen);	/* data length */
   1252 		fdc->sc_state = COPYCOMPLETE;
   1253 		/* allow 2 seconds for operation */
   1254 		timeout(fdctimeout, fdc, 2 * hz);
   1255 		return 1;				/* will return later */
   1256 
   1257 	case DOIOHALF:
   1258 	doiohalf:
   1259 		DPRINTF((" DOIOHALF:\n"));
   1260 
   1261 #ifdef DIAGNOSTIC
   1262 		type = fd->sc_type;
   1263 		sectrac = type->sectrac;
   1264 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
   1265 		sec = pos / (1 << (type->secsize - 2));
   1266 		head = (fd->sc_blkno
   1267 			% (type->seccyl * (1 << (type->secsize - 2))))
   1268 			 / (type->sectrac * (1 << (type->secsize - 2)));
   1269 		{int block;
   1270 		 block = ((fd->sc_cylin * type->heads + head) * type->sectrac + sec)
   1271 			 * (1 << (type->secsize - 2));
   1272 		 block += (fd->sc_part == SEC_P01) ? 1 : 0;
   1273 		 if (block != fd->sc_blkno) {
   1274 			 printf("fdcintr: block %d != blkno %d\n", block, fd->sc_blkno);
   1275 #ifdef DDB
   1276 			 Debugger();
   1277 #endif
   1278 		 }}
   1279 #endif
   1280 		if ((read = bp->b_flags & B_READ)) {
   1281 			bcopy(fd->sc_copybuf
   1282 			      + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
   1283 			      bp->b_data + fd->sc_skip,
   1284 			      FDC_BSIZE);
   1285 			fdc->sc_state = IOCOMPLETE;
   1286 			goto iocomplete2;
   1287 		} else {
   1288 			bcopy(bp->b_data + fd->sc_skip,
   1289 			      fd->sc_copybuf
   1290 			      + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
   1291 			      FDC_BSIZE);
   1292 			fdc_dmastart(fdc, read, fd->sc_copybuf, 1024);
   1293 		}
   1294 		out_fdc(iot, ioh, NE7CMD_WRITE);	/* WRITE */
   1295 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1296 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
   1297 		out_fdc(iot, ioh, head);
   1298 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
   1299 		out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */
   1300 		out_fdc(iot, ioh, sectrac);		/* sectors/track */
   1301 		out_fdc(iot, ioh, fd->sc_type->gap1);	/* gap1 size */
   1302 		out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */
   1303 		fdc->sc_state = IOCOMPLETE;
   1304 		/* allow 2 seconds for operation */
   1305 		timeout(fdctimeout, fdc, 2 * hz);
   1306 		return 1;				/* will return later */
   1307 
   1308 	case SEEKWAIT:
   1309 		untimeout(fdctimeout, fdc);
   1310 		fdc->sc_state = SEEKCOMPLETE;
   1311 		/* allow 1/50 second for heads to settle */
   1312 #if 0
   1313 		timeout(fdcpseudointr, fdc, hz / 50);
   1314 #endif
   1315 		return 1;
   1316 
   1317 	case SEEKCOMPLETE:
   1318 		/* Make sure seek really happened */
   1319 		DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
   1320 			 bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts)));
   1321 		out_fdc(iot, ioh, NE7CMD_SENSEI);
   1322 		tmp = fdcresult(fdc);
   1323 		if ((st0 & 0xf8) == 0xc0) {
   1324 			DPRINTF(("fdcintr: first seek!\n"));
   1325 			fdc->sc_state = DORECAL;
   1326 			goto loop;
   1327 		} else if (tmp != 2 ||
   1328 			   (st0 & 0xf8) != 0x20 ||
   1329 			   cyl != bp->b_cylinder) {
   1330 #ifdef FDDEBUG
   1331 			fdcstatus(&fd->sc_dev, 2, "seek failed");
   1332 #endif
   1333 			fdcretry(fdc);
   1334 			goto loop;
   1335 		}
   1336 		fd->sc_cylin = bp->b_cylinder;
   1337 		goto doio;
   1338 
   1339 	case IOTIMEDOUT:
   1340 #if 0
   1341 		isa_dmaabort(fdc->sc_drq);
   1342 #endif
   1343 	case SEEKTIMEDOUT:
   1344 	case RECALTIMEDOUT:
   1345 	case RESETTIMEDOUT:
   1346 		fdcretry(fdc);
   1347 		goto loop;
   1348 
   1349 	case IOCOMPLETE: /* IO DONE, post-analyze */
   1350 		untimeout(fdctimeout, fdc);
   1351 		DPRINTF(("fdcintr: in IOCOMPLETE\n"));
   1352 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
   1353 			printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
   1354 #if 0
   1355 			isa_dmaabort(fdc->sc_drq);
   1356 #endif
   1357 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
   1358 				  "read failed" : "write failed");
   1359 			printf("blkno %d nblks %d\n",
   1360 			    fd->sc_blkno, fd->sc_nblks);
   1361 			fdcretry(fdc);
   1362 			goto loop;
   1363 		}
   1364 #if 0
   1365 		isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
   1366 		    nblks * FDC_BSIZE, fdc->sc_drq);
   1367 #endif
   1368 	iocomplete2:
   1369 		if (fdc->sc_errors) {
   1370 			diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
   1371 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
   1372 			printf("\n");
   1373 			fdc->sc_errors = 0;
   1374 		}
   1375 		fd->sc_blkno += fd->sc_nblks;
   1376 		fd->sc_skip += fd->sc_nbytes;
   1377 		fd->sc_bcount -= fd->sc_nbytes;
   1378 		DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
   1379 		if (fd->sc_bcount > 0) {
   1380 			bp->b_cylinder = fd->sc_blkno
   1381 				/ (fd->sc_type->seccyl
   1382 				   * (1 << (fd->sc_type->secsize - 2)));
   1383 			goto doseek;
   1384 		}
   1385 		fdfinish(fd, bp);
   1386 		goto loop;
   1387 
   1388 	case COPYCOMPLETE: /* IO DONE, post-analyze */
   1389 		DPRINTF(("fdcintr: COPYCOMPLETE:"));
   1390 		untimeout(fdctimeout, fdc);
   1391 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
   1392 			printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
   1393 #if 0
   1394 			isa_dmaabort(fdc->sc_drq);
   1395 #endif
   1396 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
   1397 				  "read failed" : "write failed");
   1398 			printf("blkno %d nblks %d\n",
   1399 			    fd->sc_blkno, fd->sc_nblks);
   1400 			fdcretry(fdc);
   1401 			goto loop;
   1402 		}
   1403 		goto doiohalf;
   1404 
   1405 	case DORESET:
   1406 		DPRINTF(("fdcintr: in DORESET\n"));
   1407 		/* try a reset, keep motor on */
   1408 		fd_set_motor(fdc, 1);
   1409 		DELAY(100);
   1410 		fd_set_motor(fdc, 0);
   1411 		fdc->sc_state = RESETCOMPLETE;
   1412 		timeout(fdctimeout, fdc, hz / 2);
   1413 		return 1;			/* will return later */
   1414 
   1415 	case RESETCOMPLETE:
   1416 		DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
   1417 		untimeout(fdctimeout, fdc);
   1418 		/* clear the controller output buffer */
   1419 		for (i = 0; i < 4; i++) {
   1420 			out_fdc(iot, ioh, NE7CMD_SENSEI);
   1421 			(void) fdcresult(fdc);
   1422 		}
   1423 
   1424 		/* fall through */
   1425 	case DORECAL:
   1426 		DPRINTF(("fdcintr: in DORECAL\n"));
   1427 		out_fdc(iot, ioh, NE7CMD_RECAL);	/* recalibrate function */
   1428 		out_fdc(iot, ioh, fd->sc_drive);
   1429 		fdc->sc_state = RECALWAIT;
   1430 		timeout(fdctimeout, fdc, 5 * hz);
   1431 		return 1;			/* will return later */
   1432 
   1433 	case RECALWAIT:
   1434 		DPRINTF(("fdcintr: in RECALWAIT\n"));
   1435 		untimeout(fdctimeout, fdc);
   1436 		fdc->sc_state = RECALCOMPLETE;
   1437 		/* allow 1/30 second for heads to settle */
   1438 #if 0
   1439 		timeout(fdcpseudointr, fdc, hz / 30);
   1440 #endif
   1441 		return 1;			/* will return later */
   1442 
   1443 	case RECALCOMPLETE:
   1444 		DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
   1445 		out_fdc(iot, ioh, NE7CMD_SENSEI);
   1446 		tmp = fdcresult(fdc);
   1447 		if ((st0 & 0xf8) == 0xc0) {
   1448 			DPRINTF(("fdcintr: first seek!\n"));
   1449 			fdc->sc_state = DORECAL;
   1450 			goto loop;
   1451 		} else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
   1452 #ifdef FDDEBUG
   1453 			fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
   1454 #endif
   1455 			fdcretry(fdc);
   1456 			goto loop;
   1457 		}
   1458 		fd->sc_cylin = 0;
   1459 		goto doseek;
   1460 
   1461 	case MOTORWAIT:
   1462 		if (fd->sc_flags & FD_MOTOR_WAIT)
   1463 			return 1;		/* time's not up yet */
   1464 		goto doseek;
   1465 
   1466 	default:
   1467 		fdcstatus(&fd->sc_dev, 0, "stray interrupt");
   1468 		return 1;
   1469 	}
   1470 #ifdef DIAGNOSTIC
   1471 	panic("fdcintr: impossible");
   1472 #endif
   1473 #undef	st0
   1474 #undef	cyl
   1475 }
   1476 
   1477 void
   1478 fdcretry(fdc)
   1479 	struct fdc_softc *fdc;
   1480 {
   1481 	struct fd_softc *fd;
   1482 	struct buf *bp;
   1483 	char bits[64];
   1484 
   1485 	DPRINTF(("fdcretry:\n"));
   1486 	fd = fdc->sc_drives.tqh_first;
   1487 	bp = BUFQ_FIRST(&fd->sc_q);
   1488 
   1489 	switch (fdc->sc_errors) {
   1490 	case 0:
   1491 		/* try again */
   1492 		fdc->sc_state = SEEKCOMPLETE;
   1493 		break;
   1494 
   1495 	case 1: case 2: case 3:
   1496 		/* didn't work; try recalibrating */
   1497 		fdc->sc_state = DORECAL;
   1498 		break;
   1499 
   1500 	case 4:
   1501 		/* still no go; reset the bastard */
   1502 		fdc->sc_state = DORESET;
   1503 		break;
   1504 
   1505 	default:
   1506 		diskerr(bp, "fd", "hard error", LOG_PRINTF,
   1507 			fd->sc_skip, (struct disklabel *)NULL);
   1508 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
   1509 						    NE7_ST0BITS, bits,
   1510 						    sizeof(bits)));
   1511 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
   1512 						   NE7_ST1BITS, bits,
   1513 						   sizeof(bits)));
   1514 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
   1515 						   NE7_ST2BITS, bits,
   1516 						   sizeof(bits)));
   1517 		printf(" cyl %d head %d sec %d)\n",
   1518 		       fdc->sc_status[3],
   1519 		       fdc->sc_status[4],
   1520 		       fdc->sc_status[5]);
   1521 
   1522 		bp->b_flags |= B_ERROR;
   1523 		bp->b_error = EIO;
   1524 		fdfinish(fd, bp);
   1525 	}
   1526 	fdc->sc_errors++;
   1527 }
   1528 
   1529 int
   1530 fdsize(dev)
   1531 	dev_t dev;
   1532 {
   1533 
   1534 	/* Swapping to floppies would not make sense. */
   1535 	return -1;
   1536 }
   1537 
   1538 int
   1539 fddump(dev, blkno, va, size)
   1540 	dev_t dev;
   1541 	daddr_t blkno;
   1542 	caddr_t va;
   1543 	size_t size;
   1544 {
   1545 
   1546 	/* Not implemented. */
   1547 	return ENXIO;
   1548 }
   1549 
   1550 int
   1551 fdioctl(dev, cmd, addr, flag, p)
   1552 	dev_t dev;
   1553 	u_long cmd;
   1554 	caddr_t addr;
   1555 	int flag;
   1556 	struct proc *p;
   1557 {
   1558 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
   1559 	struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
   1560 	int unit = FDUNIT(dev);
   1561 	int part = DISKPART(dev);
   1562 	struct disklabel buffer;
   1563 	int error;
   1564 
   1565 	DPRINTF(("fdioctl:\n"));
   1566 	switch (cmd) {
   1567 	case DIOCGDINFO:
   1568 #if 1
   1569 		*(struct disklabel *)addr = *(fd->sc_dk.dk_label);
   1570 		return(0);
   1571 #else
   1572 		memset(&buffer, 0, sizeof(buffer));
   1573 
   1574 		buffer.d_secpercyl = fd->sc_type->seccyl;
   1575 		buffer.d_type = DTYPE_FLOPPY;
   1576 		buffer.d_secsize = 128 << fd->sc_type->secsize;
   1577 
   1578 		if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
   1579 			return EINVAL;
   1580 
   1581 		*(struct disklabel *)addr = buffer;
   1582 		return 0;
   1583 #endif
   1584 
   1585 	case DIOCGPART:
   1586 		((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
   1587 		((struct partinfo *)addr)->part =
   1588 		    &fd->sc_dk.dk_label->d_partitions[part];
   1589 		return(0);
   1590 
   1591 	case DIOCWLABEL:
   1592 		if ((flag & FWRITE) == 0)
   1593 			return EBADF;
   1594 		/* XXX do something */
   1595 		return 0;
   1596 
   1597 	case DIOCWDINFO:
   1598 		if ((flag & FWRITE) == 0)
   1599 			return EBADF;
   1600 
   1601 		error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
   1602 		if (error)
   1603 			return error;
   1604 
   1605 		error = writedisklabel(dev, fdstrategy, &buffer, NULL);
   1606 		return error;
   1607 
   1608 	case DIOCLOCK:
   1609 		/*
   1610 		 * Nothing to do here, really.
   1611 		 */
   1612 		return 0; /* XXX */
   1613 
   1614 	case DIOCEJECT:
   1615 		if (*(int *)addr == 0) {
   1616 			/*
   1617 			 * Don't force eject: check that we are the only
   1618 			 * partition open. If so, unlock it.
   1619 			 */
   1620 			if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 ||
   1621 			    fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask !=
   1622 			    fd->sc_dk.dk_openmask) {
   1623 				return (EBUSY);
   1624 			}
   1625 		}
   1626 		/* FALLTHROUGH */
   1627 	case ODIOCEJECT:
   1628 		fd_do_eject(fdc, unit);
   1629 		return 0;
   1630 
   1631 	default:
   1632 		return ENOTTY;
   1633 	}
   1634 
   1635 #ifdef DIAGNOSTIC
   1636 	panic("fdioctl: impossible");
   1637 #endif
   1638 }
   1639 
   1640 void
   1641 fd_do_eject(fdc, unit)
   1642 	struct fdc_softc *fdc;
   1643 	int unit;
   1644 {
   1645 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
   1646 			  0x20 | ( 1 << unit));
   1647 	DELAY(1); /* XXX */
   1648 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20);
   1649 }
   1650 
   1651 /*
   1652  * Build disk label. For now we only create a label from what we know
   1653  * from 'sc'.
   1654  */
   1655 static int
   1656 fdgetdisklabel(sc, dev)
   1657 	struct fd_softc *sc;
   1658 	dev_t dev;
   1659 {
   1660 	struct disklabel *lp;
   1661 	int part;
   1662 
   1663 	DPRINTF(("fdgetdisklabel()\n"));
   1664 
   1665 	part = DISKPART(dev);
   1666 	lp = sc->sc_dk.dk_label;
   1667 	bzero(lp, sizeof(struct disklabel));
   1668 
   1669 	lp->d_secsize     = 128 << sc->sc_type->secsize;
   1670 	lp->d_ntracks     = sc->sc_type->heads;
   1671 	lp->d_nsectors    = sc->sc_type->sectrac;
   1672 	lp->d_secpercyl   = lp->d_ntracks * lp->d_nsectors;
   1673 	lp->d_ncylinders  = sc->sc_type->size / lp->d_secpercyl;
   1674 	lp->d_secperunit  = sc->sc_type->size;
   1675 
   1676 	lp->d_type        = DTYPE_FLOPPY;
   1677 	lp->d_rpm         = 300; 	/* XXX */
   1678 	lp->d_interleave  = 1;		/* FIXME: is this OK?		*/
   1679 	lp->d_bbsize      = 0;
   1680 	lp->d_sbsize      = 0;
   1681 	lp->d_npartitions = part + 1;
   1682 #define STEP_DELAY	6000	/* 6ms (6000us) delay after stepping	*/
   1683 	lp->d_trkseek     = STEP_DELAY; /* XXX */
   1684 	lp->d_magic       = DISKMAGIC;
   1685 	lp->d_magic2      = DISKMAGIC;
   1686 	lp->d_checksum    = dkcksum(lp);
   1687 	lp->d_partitions[part].p_size   = lp->d_secperunit;
   1688 	lp->d_partitions[part].p_fstype = FS_UNUSED;
   1689 	lp->d_partitions[part].p_fsize  = 1024;
   1690 	lp->d_partitions[part].p_frag   = 8;
   1691 
   1692 	return(0);
   1693 }
   1694 
   1695 #include <dev/cons.h>
   1696 
   1697 /*
   1698  * Mountroot hook: prompt the user to enter the root file system
   1699  * floppy.
   1700  */
   1701 void
   1702 fd_mountroot_hook(dev)
   1703 	struct device *dev;
   1704 {
   1705 	struct fd_softc *fd = (void*) dev;
   1706 	struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
   1707 	int c;
   1708 
   1709 	fd_do_eject(fdc, dev->dv_unit);
   1710 	printf("Insert filesystem floppy and press return.");
   1711 	for (;;) {
   1712 		c = cngetc();
   1713 		if ((c == '\r') || (c == '\n')) {
   1714 			printf("\n");
   1715 			break;
   1716 		}
   1717 	}
   1718 }
   1719