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