Home | History | Annotate | Line # | Download | only in dev
fd.c revision 1.37.4.1
      1 /*	$NetBSD: fd.c,v 1.37.4.1 2001/10/10 11:56:47 fvdl Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Charles M. Hannum and Minoura Makoto.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 /*-
     40  * Copyright (c) 1990 The Regents of the University of California.
     41  * All rights reserved.
     42  *
     43  * This code is derived from software contributed to Berkeley by
     44  * Don Ahn.
     45  *
     46  * Redistribution and use in source and binary forms, with or without
     47  * modification, are permitted provided that the following conditions
     48  * are met:
     49  * 1. Redistributions of source code must retain the above copyright
     50  *    notice, this list of conditions and the following disclaimer.
     51  * 2. Redistributions in binary form must reproduce the above copyright
     52  *    notice, this list of conditions and the following disclaimer in the
     53  *    documentation and/or other materials provided with the distribution.
     54  * 3. All advertising materials mentioning features or use of this software
     55  *    must display the following acknowledgement:
     56  *	This product includes software developed by the University of
     57  *	California, Berkeley and its contributors.
     58  * 4. Neither the name of the University nor the names of its contributors
     59  *    may be used to endorse or promote products derived from this software
     60  *    without specific prior written permission.
     61  *
     62  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     63  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     64  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     65  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     66  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     67  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     68  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     69  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     70  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     71  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     72  * SUCH DAMAGE.
     73  *
     74  *	@(#)fd.c	7.4 (Berkeley) 5/25/91
     75  */
     76 
     77 #include "rnd.h"
     78 #include "opt_ddb.h"
     79 #include "opt_m680x0.h"
     80 
     81 #include <sys/param.h>
     82 #include <sys/systm.h>
     83 #include <sys/callout.h>
     84 #include <sys/kernel.h>
     85 #include <sys/conf.h>
     86 #include <sys/file.h>
     87 #include <sys/stat.h>
     88 #include <sys/ioctl.h>
     89 #include <sys/malloc.h>
     90 #include <sys/device.h>
     91 #include <sys/disklabel.h>
     92 #include <sys/dkstat.h>
     93 #include <sys/disk.h>
     94 #include <sys/buf.h>
     95 #include <sys/uio.h>
     96 #include <sys/syslog.h>
     97 #include <sys/queue.h>
     98 #include <sys/fdio.h>
     99 #include <sys/vnode.h>
    100 #if NRND > 0
    101 #include <sys/rnd.h>
    102 #endif
    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 transferring */
    236 	int sc_nbytes;		/* number of bytes currently transferring */
    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 *, struct vnode *));
    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,
    453 			      DMAC_MAXSEGSZ, 0,
    454 			      BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
    455 			      &fdc->sc_dmamap)) {
    456 		printf("%s: can't set up intio DMA map\n",
    457 		    fdc->sc_dev.dv_xname);
    458 		return;
    459 	}
    460 
    461 	if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc))
    462 		panic ("Could not establish interrupt (duplicated vector?).");
    463 	intio_set_ivec(ia->ia_intr);
    464 
    465 	/* reset */
    466 	intio_disable_intr(SICILIAN_INTR_FDD);
    467 	intio_enable_intr(SICILIAN_INTR_FDC);
    468 	fdcresult(fdc);
    469 	fdcreset(fdc);
    470 
    471 	printf("%s: uPD72065 FDC\n", fdc->sc_dev.dv_xname);
    472 	out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
    473 	out_fdc(iot, ioh, 0xd0);
    474 	out_fdc(iot, ioh, 0x10);
    475 
    476 	/* physical limit: four drives per controller. */
    477 	for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
    478 		(void)config_found(self, (void *)&fa, fdprint);
    479 	}
    480 
    481 	intio_enable_intr(SICILIAN_INTR_FDC);
    482 }
    483 
    484 void
    485 fdcreset(fdc)
    486 	struct fdc_softc *fdc;
    487 {
    488 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdsts, NE7CMD_RESET);
    489 }
    490 
    491 static int
    492 fdcpoll(fdc)
    493 	struct fdc_softc *fdc;
    494 {
    495 	int i = 25000, n;
    496 	while (--i > 0) {
    497 		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
    498 			out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
    499 			n = fdcresult(fdc);
    500 			break;
    501 		}
    502 		DELAY(100);
    503 	}
    504 	return i;
    505 }
    506 
    507 int
    508 fdprobe(parent, cf, aux)
    509 	struct device *parent;
    510 	struct cfdata *cf;
    511 	void *aux;
    512 {
    513 	struct fdc_softc *fdc = (void *)parent;
    514 	struct fd_type *type;
    515 	struct fdc_attach_args *fa = aux;
    516 	int drive = fa->fa_drive;
    517 	bus_space_tag_t iot = fdc->sc_iot;
    518 	bus_space_handle_t ioh = fdc->sc_ioh;
    519 	int n;
    520 	int found = 0;
    521 	int i;
    522 
    523 	if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
    524 	    cf->cf_loc[FDCCF_UNIT] != drive)
    525 		return 0;
    526 
    527 	type = &fd_types[0];	/* XXX 1.2MB */
    528 
    529 	intio_disable_intr(SICILIAN_INTR_FDC);
    530 
    531 	/* select drive and turn on motor */
    532 	bus_space_write_1(iot, ioh, fdctl, 0x80 | (type->rate << 4)| drive);
    533 	fdc_force_ready(FDCRDY);
    534 	fdcpoll(fdc);
    535 
    536 retry:
    537 	out_fdc(iot, ioh, NE7CMD_RECAL);
    538 	out_fdc(iot, ioh, drive);
    539 
    540 	i = 25000;
    541 	while (--i > 0) {
    542 		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
    543 			out_fdc(iot, ioh, NE7CMD_SENSEI);
    544 			n = fdcresult(fdc);
    545 			break;
    546 		}
    547 		DELAY(100);
    548 	}
    549 
    550 #ifdef FDDEBUG
    551 	{
    552 		int i;
    553 		DPRINTF(("fdprobe: status"));
    554 		for (i = 0; i < n; i++)
    555 			DPRINTF((" %x", fdc->sc_status[i]));
    556 		DPRINTF(("\n"));
    557 	}
    558 #endif
    559 
    560 	if (n == 2) {
    561 		if ((fdc->sc_status[0] & 0xf0) == 0x20) {
    562 			found = 1;
    563 		} else if ((fdc->sc_status[0] & 0xf0) == 0xc0) {
    564 			goto retry;
    565 		}
    566 	}
    567 
    568 	/* turn off motor */
    569 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh,
    570 			  fdctl, (type->rate << 4)| drive);
    571 	fdc_force_ready(FDCSTBY);
    572 	if (!found) {
    573 		intio_enable_intr(SICILIAN_INTR_FDC);
    574 		return 0;
    575 	}
    576 
    577 	return 1;
    578 }
    579 
    580 /*
    581  * Controller is working, and drive responded.  Attach it.
    582  */
    583 void
    584 fdattach(parent, self, aux)
    585 	struct device *parent, *self;
    586 	void *aux;
    587 {
    588 	struct fdc_softc *fdc = (void *)parent;
    589 	struct fd_softc *fd = (void *)self;
    590 	struct fdc_attach_args *fa = aux;
    591 	struct fd_type *type = &fd_types[0];	/* XXX 1.2MB */
    592 	int drive = fa->fa_drive;
    593 
    594 	callout_init(&fd->sc_motoron_ch);
    595 	callout_init(&fd->sc_motoroff_ch);
    596 
    597 	fd->sc_flags = 0;
    598 
    599 	if (type)
    600 		printf(": %s, %d cyl, %d head, %d sec\n", type->name,
    601 		       type->cyls, type->heads, type->sectrac);
    602 	else
    603 		printf(": density unknown\n");
    604 
    605 	BUFQ_INIT(&fd->sc_q);
    606 	fd->sc_cylin = -1;
    607 	fd->sc_drive = drive;
    608 	fd->sc_deftype = type;
    609 	fdc->sc_fd[drive] = fd;
    610 
    611 	fd->sc_copybuf = (u_char *)malloc(NBPG, M_DEVBUF, M_WAITOK);
    612 	if (fd->sc_copybuf == 0)
    613 		printf("fdprobe: WARNING!! malloc() failed.\n");
    614 	fd->sc_flags |= FD_ALIVE;
    615 
    616 	/*
    617 	 * Initialize and attach the disk structure.
    618 	 */
    619 	fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
    620 	fd->sc_dk.dk_driver = &fddkdriver;
    621 	disk_attach(&fd->sc_dk);
    622 
    623 	/*
    624 	 * Establish a mountroot_hook anyway in case we booted
    625 	 * with RB_ASKNAME and get selected as the boot device.
    626 	 */
    627 	mountroothook_establish(fd_mountroot_hook, &fd->sc_dev);
    628 
    629 #if NRND > 0
    630 	rnd_attach_source(&fd->rnd_source, fd->sc_dev.dv_xname,
    631 			  RND_TYPE_DISK, 0);
    632 #endif
    633 }
    634 
    635 __inline struct fd_type *
    636 fd_dev_to_type(fd, dev)
    637 	struct fd_softc *fd;
    638 	dev_t dev;
    639 {
    640 	int type = FDTYPE(dev);
    641 
    642 	if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
    643 		return NULL;
    644 	return &fd_types[type];
    645 }
    646 
    647 void
    648 fdstrategy(bp)
    649 	register struct buf *bp;	/* IO operation to perform */
    650 {
    651 	struct fd_softc *fd;
    652 	int unit = FDUNIT(vdev_rdev(bp->b_devvp));
    653 	int sz;
    654  	int s;
    655 
    656 	fd = vdev_privdata(bp->b_devvp);
    657 	if (fd == NULL ||
    658 	    bp->b_blkno < 0 ||
    659 	    (bp->b_bcount % FDC_BSIZE) != 0) {
    660 		DPRINTF(("fdstrategy: unit=%d, blkno=%d, bcount=%d\n", unit,
    661 			 bp->b_blkno, bp->b_bcount));
    662 		bp->b_error = EINVAL;
    663 		goto bad;
    664 	}
    665 
    666 	/* If it's a null transfer, return immediately. */
    667 	if (bp->b_bcount == 0)
    668 		goto done;
    669 
    670 	sz = howmany(bp->b_bcount, FDC_BSIZE);
    671 
    672 	if (bp->b_blkno + sz > (fd->sc_type->size << (fd->sc_type->secsize - 2))) {
    673 		sz = (fd->sc_type->size << (fd->sc_type->secsize - 2)) - bp->b_blkno;
    674 		if (sz == 0) {
    675 			/* If exactly at end of disk, return EOF. */
    676 			bp->b_resid = bp->b_bcount;
    677 			goto done;
    678 		}
    679 		if (sz < 0) {
    680 			/* If past end of disk, return EINVAL. */
    681 			bp->b_error = EINVAL;
    682 			goto bad;
    683 		}
    684 		/* Otherwise, truncate request. */
    685 		bp->b_bcount = sz << DEV_BSHIFT;
    686 	}
    687 
    688 	bp->b_rawblkno = bp->b_blkno;
    689  	bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE)
    690 		/ (fd->sc_type->seccyl * (1 << (fd->sc_type->secsize - 2)));
    691 
    692 	DPRINTF(("fdstrategy: %s b_blkno %d b_bcount %ld cylin %ld\n",
    693 		 bp->b_flags & B_READ ? "read" : "write",
    694 		 bp->b_blkno, bp->b_bcount, bp->b_cylinder));
    695 	/* Queue transfer on drive, activate drive and controller if idle. */
    696 	s = splbio();
    697 	disksort_cylinder(&fd->sc_q, bp);
    698 	callout_stop(&fd->sc_motoroff_ch);		/* a good idea */
    699 	if (fd->sc_active == 0)
    700 		fdstart(fd);
    701 #ifdef DIAGNOSTIC
    702 	else {
    703 		struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    704 		if (fdc->sc_state == DEVIDLE) {
    705 			printf("fdstrategy: controller inactive\n");
    706 			fdcstart(fdc);
    707 		}
    708 	}
    709 #endif
    710 	splx(s);
    711 	return;
    712 
    713 bad:
    714 	bp->b_flags |= B_ERROR;
    715 done:
    716 	/* Toss transfer; we're done early. */
    717 	biodone(bp);
    718 }
    719 
    720 void
    721 fdstart(fd)
    722 	struct fd_softc *fd;
    723 {
    724 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    725 	int active = fdc->sc_drives.tqh_first != 0;
    726 
    727 	/* Link into controller queue. */
    728 	fd->sc_active = 1;
    729 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    730 
    731 	/* If controller not already active, start it. */
    732 	if (!active)
    733 		fdcstart(fdc);
    734 }
    735 
    736 void
    737 fdfinish(fd, bp)
    738 	struct fd_softc *fd;
    739 	struct buf *bp;
    740 {
    741 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    742 
    743 	/*
    744 	 * Move this drive to the end of the queue to give others a `fair'
    745 	 * chance.  We only force a switch if N operations are completed while
    746 	 * another drive is waiting to be serviced, since there is a long motor
    747 	 * startup delay whenever we switch.
    748 	 */
    749 	if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
    750 		fd->sc_ops = 0;
    751 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
    752 		if (BUFQ_NEXT(bp) != NULL) {
    753 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    754 		} else
    755 			fd->sc_active = 0;
    756 	}
    757 	bp->b_resid = fd->sc_bcount;
    758 	fd->sc_skip = 0;
    759 	BUFQ_REMOVE(&fd->sc_q, bp);
    760 
    761 #if NRND > 0
    762 	rnd_add_uint32(&fd->rnd_source, bp->b_blkno);
    763 #endif
    764 
    765 	biodone(bp);
    766 	/* turn off motor 5s from now */
    767 	callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
    768 	fdc->sc_state = DEVIDLE;
    769 }
    770 
    771 int
    772 fdread(devvp, uio, flags)
    773 	struct vnode *devvp;
    774 	struct uio *uio;
    775 	int flags;
    776 {
    777 
    778 	return (physio(fdstrategy, NULL, devvp, B_READ, minphys, uio));
    779 }
    780 
    781 int
    782 fdwrite(devvp, uio, flags)
    783 	struct vnode *devvp;
    784 	struct uio *uio;
    785 	int flags;
    786 {
    787 
    788 	return (physio(fdstrategy, NULL, devvp, B_WRITE, minphys, uio));
    789 }
    790 
    791 void
    792 fd_set_motor(fdc, reset)
    793 	struct fdc_softc *fdc;
    794 	int reset;
    795 {
    796 	struct fd_softc *fd;
    797 	int n;
    798 
    799 	DPRINTF(("fd_set_motor:\n"));
    800 	for (n = 0; n < 4; n++)
    801 		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR)) {
    802 			bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdctl,
    803 					  0x80 | (fd->sc_type->rate << 4)| n);
    804 		}
    805 }
    806 
    807 void
    808 fd_motor_off(arg)
    809 	void *arg;
    810 {
    811 	struct fd_softc *fd = arg;
    812 	struct fdc_softc *fdc = (struct fdc_softc*) fd->sc_dev.dv_parent;
    813 	int s;
    814 
    815 	DPRINTF(("fd_motor_off:\n"));
    816 
    817 	s = splbio();
    818 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
    819 	bus_space_write_1 (fdc->sc_iot, fdc->sc_ioh, fdctl,
    820 			   (fd->sc_type->rate << 4) | fd->sc_drive);
    821 #if 0
    822 	fd_set_motor(fdc, 0); /* XXX */
    823 #endif
    824 	splx(s);
    825 }
    826 
    827 void
    828 fd_motor_on(arg)
    829 	void *arg;
    830 {
    831 	struct fd_softc *fd = arg;
    832 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    833 	int s;
    834 
    835 	DPRINTF(("fd_motor_on:\n"));
    836 
    837 	s = splbio();
    838 	fd->sc_flags &= ~FD_MOTOR_WAIT;
    839 	if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
    840 		(void) fdcintr(fdc);
    841 	splx(s);
    842 }
    843 
    844 int
    845 fdcresult(fdc)
    846 	struct fdc_softc *fdc;
    847 {
    848 	bus_space_tag_t iot = fdc->sc_iot;
    849 	bus_space_handle_t ioh = fdc->sc_ioh;
    850 	u_char i;
    851 	int j = 100000,
    852 	    n = 0;
    853 
    854 	for (; j; j--) {
    855 		i = bus_space_read_1(iot, ioh, fdsts) &
    856 		  (NE7_DIO | NE7_RQM | NE7_CB);
    857 
    858 		if (i == NE7_RQM)
    859 			return n;
    860 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
    861 			if (n >= sizeof(fdc->sc_status)) {
    862 				log(LOG_ERR, "fdcresult: overrun\n");
    863 				return -1;
    864 			}
    865 			fdc->sc_status[n++] =
    866 			  bus_space_read_1(iot, ioh, fddata);
    867 		}
    868 		delay(10);
    869 	}
    870 	log(LOG_ERR, "fdcresult: timeout\n");
    871 	return -1;
    872 }
    873 
    874 int
    875 out_fdc(iot, ioh, x)
    876 	bus_space_tag_t iot;
    877 	bus_space_handle_t ioh;
    878 	u_char x;
    879 {
    880 	int i = 100000;
    881 
    882 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
    883 	if (i <= 0)
    884 		return -1;
    885 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
    886 	if (i <= 0)
    887 		return -1;
    888 	bus_space_write_1(iot, ioh, fddata, x);
    889 	return 0;
    890 }
    891 
    892 int
    893 fdopen(devvp, flags, mode, p)
    894 	struct vnode *devvp;
    895 	int flags, mode;
    896 	struct proc *p;
    897 {
    898  	int unit;
    899 	dev_t dev;
    900 	struct fd_softc *fd;
    901 	struct fd_type *type;
    902 	struct fdc_softc *fdc;
    903 
    904 	dev = vdev_rdev(devvp);
    905 	unit = FDUNIT(dev);
    906 	if (unit >= fd_cd.cd_ndevs)
    907 		return ENXIO;
    908 	fd = fd_cd.cd_devs[unit];
    909 	if (fd == 0)
    910 		return ENXIO;
    911 	type = fd_dev_to_type(fd, dev);
    912 	if (type == NULL)
    913 		return ENXIO;
    914 
    915 	if ((fd->sc_flags & FD_OPEN) != 0 &&
    916 	    fd->sc_type != type)
    917 		return EBUSY;
    918 
    919 	vdev_setprivdata(devvp, fd);
    920 
    921 	fdc = (void *)fd->sc_dev.dv_parent;
    922 	if ((fd->sc_flags & FD_OPEN) == 0) {
    923 		/* Lock eject button */
    924 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
    925 				  0x40 | ( 1 << unit));
    926 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x40);
    927 	}
    928 
    929 	fd->sc_type = type;
    930 	fd->sc_cylin = -1;
    931 
    932 	switch (mode) {
    933 	case S_IFCHR:
    934 		fd->sc_flags |= FD_COPEN;
    935 		break;
    936 	case S_IFBLK:
    937 		fd->sc_flags |= FD_BOPEN;
    938 		break;
    939 	}
    940 
    941 	fdgetdisklabel(fd, devvp);
    942 
    943 	return 0;
    944 }
    945 
    946 int
    947 fdclose(devvp, flags, mode, p)
    948 	struct vnode *devvp;
    949 	int flags, mode;
    950 	struct proc *p;
    951 {
    952 	struct fd_softc *fd = vdev_privdata(devvp);
    953 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
    954 	int unit;
    955 
    956 	unit = FDUNIT(vdev_rdev(devvp));
    957 	DPRINTF(("fdclose %d\n", unit));
    958 
    959 	switch (mode) {
    960 	case S_IFCHR:
    961 		fd->sc_flags &= ~FD_COPEN;
    962 		break;
    963 	case S_IFBLK:
    964 		fd->sc_flags &= ~FD_BOPEN;
    965 		break;
    966 	}
    967 
    968 	if ((fd->sc_flags & FD_OPEN) == 0) {
    969 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
    970 				  ( 1 << unit));
    971 		bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0);
    972 	}
    973 	return 0;
    974 }
    975 
    976 void
    977 fdcstart(fdc)
    978 	struct fdc_softc *fdc;
    979 {
    980 
    981 #ifdef DIAGNOSTIC
    982 	/* only got here if controller's drive queue was inactive; should
    983 	   be in idle state */
    984 	if (fdc->sc_state != DEVIDLE) {
    985 		printf("fdcstart: not idle\n");
    986 		return;
    987 	}
    988 #endif
    989 	(void) fdcintr(fdc);
    990 }
    991 
    992 void
    993 fdcstatus(dv, n, s)
    994 	struct device *dv;
    995 	int n;
    996 	char *s;
    997 {
    998 	struct fdc_softc *fdc = (void *)dv->dv_parent;
    999 	char bits[64];
   1000 
   1001 	if (n == 0) {
   1002 		out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
   1003 		(void) fdcresult(fdc);
   1004 		n = 2;
   1005 	}
   1006 
   1007 	printf("%s: %s: state %d", dv->dv_xname, s, fdc->sc_state);
   1008 
   1009 	switch (n) {
   1010 	case 0:
   1011 		printf("\n");
   1012 		break;
   1013 	case 2:
   1014 		printf(" (st0 %s cyl %d)\n",
   1015 		    bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
   1016 		    bits, sizeof(bits)), fdc->sc_status[1]);
   1017 		break;
   1018 	case 7:
   1019 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
   1020 		    NE7_ST0BITS, bits, sizeof(bits)));
   1021 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
   1022 		    NE7_ST1BITS, bits, sizeof(bits)));
   1023 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
   1024 		    NE7_ST2BITS, bits, sizeof(bits)));
   1025 		printf(" cyl %d head %d sec %d)\n",
   1026 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
   1027 		break;
   1028 #ifdef DIAGNOSTIC
   1029 	default:
   1030 		printf(" fdcstatus: weird size: %d\n", n);
   1031 		break;
   1032 #endif
   1033 	}
   1034 }
   1035 
   1036 void
   1037 fdctimeout(arg)
   1038 	void *arg;
   1039 {
   1040 	struct fdc_softc *fdc = arg;
   1041 	struct fd_softc *fd = fdc->sc_drives.tqh_first;
   1042 	int s;
   1043 
   1044 	s = splbio();
   1045 	fdcstatus(&fd->sc_dev, 0, "timeout");
   1046 
   1047 	if (BUFQ_FIRST(&fd->sc_q) != NULL)
   1048 		fdc->sc_state++;
   1049 	else
   1050 		fdc->sc_state = DEVIDLE;
   1051 
   1052 	(void) fdcintr(fdc);
   1053 	splx(s);
   1054 }
   1055 
   1056 #if 0
   1057 void
   1058 fdcpseudointr(arg)
   1059 	void *arg;
   1060 {
   1061 	int s;
   1062 	struct fdc_softc *fdc = arg;
   1063 
   1064 	/* just ensure it has the right spl */
   1065 	s = splbio();
   1066 	(void) fdcintr(fdc);
   1067 	splx(s);
   1068 }
   1069 #endif
   1070 
   1071 int
   1072 fdcintr(arg)
   1073 	void *arg;
   1074 {
   1075 	struct fdc_softc *fdc = arg;
   1076 #define	st0	fdc->sc_status[0]
   1077 #define	cyl	fdc->sc_status[1]
   1078 	struct fd_softc *fd;
   1079 	struct buf *bp;
   1080 	bus_space_tag_t iot = fdc->sc_iot;
   1081 	bus_space_handle_t ioh = fdc->sc_ioh;
   1082 	int read, head, sec, pos, i, sectrac, nblks;
   1083 	int	tmp;
   1084 	struct fd_type *type;
   1085 
   1086 loop:
   1087 	fd = fdc->sc_drives.tqh_first;
   1088 	if (fd == NULL) {
   1089 		DPRINTF(("fdcintr: set DEVIDLE\n"));
   1090 		if (fdc->sc_state == DEVIDLE) {
   1091 			if (intio_get_sicilian_intr() & SICILIAN_STAT_FDC) {
   1092 				out_fdc(iot, ioh, NE7CMD_SENSEI);
   1093 				if ((tmp = fdcresult(fdc)) != 2 ||
   1094 				    (st0 & 0xf8) != 0x20) {
   1095 					goto loop;
   1096 				}
   1097 			}
   1098 		}
   1099 		/* no drives waiting; end */
   1100 		fdc->sc_state = DEVIDLE;
   1101  		return 1;
   1102 	}
   1103 
   1104 	/* Is there a transfer to this drive?  If not, deactivate drive. */
   1105 	bp = BUFQ_FIRST(&fd->sc_q);
   1106 	if (bp == NULL) {
   1107 		fd->sc_ops = 0;
   1108 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
   1109 		fd->sc_active = 0;
   1110 		goto loop;
   1111 	}
   1112 
   1113 	switch (fdc->sc_state) {
   1114 	case DEVIDLE:
   1115 		DPRINTF(("fdcintr: in DEVIDLE\n"));
   1116 		fdc->sc_errors = 0;
   1117 		fd->sc_skip = 0;
   1118 		fd->sc_bcount = bp->b_bcount;
   1119 		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
   1120 		callout_stop(&fd->sc_motoroff_ch);
   1121 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
   1122 			fdc->sc_state = MOTORWAIT;
   1123 			return 1;
   1124 		}
   1125 		if ((fd->sc_flags & FD_MOTOR) == 0) {
   1126 			/* Turn on the motor */
   1127 			/* being careful about other drives. */
   1128 			for (i = 0; i < 4; i++) {
   1129 				struct fd_softc *ofd = fdc->sc_fd[i];
   1130 				if (ofd && ofd->sc_flags & FD_MOTOR) {
   1131 					callout_stop(&ofd->sc_motoroff_ch);
   1132 					ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
   1133 					break;
   1134 				}
   1135 			}
   1136 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
   1137 			fd_set_motor(fdc, 0);
   1138 			fdc->sc_state = MOTORWAIT;
   1139 			/* allow .5s for motor to stabilize */
   1140 			callout_reset(&fd->sc_motoron_ch, hz / 2,
   1141 			    fd_motor_on, fd);
   1142 			return 1;
   1143 		}
   1144 		/* Make sure the right drive is selected. */
   1145 		fd_set_motor(fdc, 0);
   1146 
   1147 		/* fall through */
   1148 	case DOSEEK:
   1149 	doseek:
   1150 		DPRINTF(("fdcintr: in DOSEEK\n"));
   1151 		if (fd->sc_cylin == bp->b_cylinder)
   1152 			goto doio;
   1153 
   1154 		out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
   1155 		out_fdc(iot, ioh, 0xd0);	/* XXX const */
   1156 		out_fdc(iot, ioh, 0x10);
   1157 
   1158 		out_fdc(iot, ioh, NE7CMD_SEEK);	/* seek function */
   1159 		out_fdc(iot, ioh, fd->sc_drive);	/* drive number */
   1160 		out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
   1161 
   1162 		fd->sc_cylin = -1;
   1163 		fdc->sc_state = SEEKWAIT;
   1164 
   1165 		fd->sc_dk.dk_seek++;
   1166 		disk_busy(&fd->sc_dk);
   1167 
   1168 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
   1169 		return 1;
   1170 
   1171 	case DOIO:
   1172 	doio:
   1173 		DPRINTF(("fdcintr: DOIO: "));
   1174 		type = fd->sc_type;
   1175 		sectrac = type->sectrac;
   1176 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
   1177 		sec = pos / (1 << (type->secsize - 2));
   1178 		if (type->secsize == 2) {
   1179 			fd->sc_part = SEC_P11;
   1180 			nblks = (sectrac - sec) << (type->secsize - 2);
   1181 			nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
   1182 			DPRINTF(("nblks(0)"));
   1183 		} else if ((fd->sc_blkno % 2) == 0) {
   1184 			if (fd->sc_bcount & 0x00000200) {
   1185 				if (fd->sc_bcount == FDC_BSIZE) {
   1186 					fd->sc_part = SEC_P10;
   1187 					nblks = 1;
   1188 					DPRINTF(("nblks(1)"));
   1189 				} else {
   1190 					fd->sc_part = SEC_P11;
   1191 					nblks = (sectrac - sec) * 2;
   1192 					nblks = min(nblks, fd->sc_bcount
   1193 						    / FDC_BSIZE - 1);
   1194 					DPRINTF(("nblks(2)"));
   1195 				}
   1196 			} else {
   1197 				fd->sc_part = SEC_P11;
   1198 				nblks = (sectrac - sec)
   1199 					<< (type->secsize - 2);
   1200 				nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
   1201 				DPRINTF(("nblks(3)"));
   1202 			}
   1203 		} else {
   1204 			fd->sc_part = SEC_P01;
   1205 			nblks = 1;
   1206 			DPRINTF(("nblks(4)"));
   1207 		}
   1208 		nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
   1209 		DPRINTF((" %d\n", nblks));
   1210 		fd->sc_nblks = nblks;
   1211 		fd->sc_nbytes = nblks * FDC_BSIZE;
   1212 		head = (fd->sc_blkno
   1213 			% (type->seccyl * (1 << (type->secsize - 2))))
   1214 			 / (type->sectrac * (1 << (type->secsize - 2)));
   1215 
   1216 #ifdef DIAGNOSTIC
   1217 		{int block;
   1218 		 block = ((fd->sc_cylin * type->heads + head) * type->sectrac
   1219 			  + sec) * (1 << (type->secsize - 2));
   1220 		 block += (fd->sc_part == SEC_P01) ? 1 : 0;
   1221 		 if (block != fd->sc_blkno) {
   1222 			 printf("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec, type->secsize);
   1223 			 printf("fdcintr: doio: block %d != blkno %d\n", block, fd->sc_blkno);
   1224 #ifdef DDB
   1225 			 Debugger();
   1226 #endif
   1227 		 }}
   1228 #endif
   1229 		read = bp->b_flags & B_READ;
   1230 		DPRINTF(("fdcintr: %s drive %d track %d head %d sec %d nblks %d, skip %d\n",
   1231 			 read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
   1232 			 head, sec, nblks, fd->sc_skip));
   1233 		DPRINTF(("C H R N: %d %d %d %d\n", fd->sc_cylin, head, sec,
   1234 			 type->secsize));
   1235 
   1236 		if (fd->sc_part != SEC_P11)
   1237 			goto docopy;
   1238 
   1239 		fdc_dmastart(fdc,
   1240 			     read, bp->b_data + fd->sc_skip, fd->sc_nbytes);
   1241 		if (read)
   1242 			out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
   1243 		else
   1244 			out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
   1245 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1246 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
   1247 		out_fdc(iot, ioh, head);
   1248 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
   1249 		out_fdc(iot, ioh, type->secsize);	/* sector size */
   1250 		out_fdc(iot, ioh, type->sectrac);	/* sectors/track */
   1251 		out_fdc(iot, ioh, type->gap1);		/* gap1 size */
   1252 		out_fdc(iot, ioh, type->datalen);	/* data length */
   1253 		fdc->sc_state = IOCOMPLETE;
   1254 
   1255 		disk_busy(&fd->sc_dk);
   1256 
   1257 		/* allow 2 seconds for operation */
   1258 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1259 		return 1;				/* will return later */
   1260 
   1261 	case DOCOPY:
   1262 	docopy:
   1263 		DPRINTF(("fdcintr: DOCOPY:\n"));
   1264 		fdc_dmastart(fdc, B_READ, fd->sc_copybuf, 1024);
   1265 		out_fdc(iot, ioh, NE7CMD_READ);		/* READ */
   1266 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1267 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
   1268 		out_fdc(iot, ioh, head);
   1269 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
   1270 		out_fdc(iot, ioh, type->secsize);	/* sector size */
   1271 		out_fdc(iot, ioh, type->sectrac);	/* sectors/track */
   1272 		out_fdc(iot, ioh, type->gap1);		/* gap1 size */
   1273 		out_fdc(iot, ioh, type->datalen);	/* data length */
   1274 		fdc->sc_state = COPYCOMPLETE;
   1275 		/* allow 2 seconds for operation */
   1276 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1277 		return 1;				/* will return later */
   1278 
   1279 	case DOIOHALF:
   1280 	doiohalf:
   1281 		DPRINTF((" DOIOHALF:\n"));
   1282 
   1283 #ifdef DIAGNOSTIC
   1284 		type = fd->sc_type;
   1285 		sectrac = type->sectrac;
   1286 		pos = fd->sc_blkno % (sectrac * (1 << (type->secsize - 2)));
   1287 		sec = pos / (1 << (type->secsize - 2));
   1288 		head = (fd->sc_blkno
   1289 			% (type->seccyl * (1 << (type->secsize - 2))))
   1290 			 / (type->sectrac * (1 << (type->secsize - 2)));
   1291 		{int block;
   1292 		 block = ((fd->sc_cylin * type->heads + head) * type->sectrac + sec)
   1293 			 * (1 << (type->secsize - 2));
   1294 		 block += (fd->sc_part == SEC_P01) ? 1 : 0;
   1295 		 if (block != fd->sc_blkno) {
   1296 			 printf("fdcintr: block %d != blkno %d\n", block, fd->sc_blkno);
   1297 #ifdef DDB
   1298 			 Debugger();
   1299 #endif
   1300 		 }}
   1301 #endif
   1302 		if ((read = bp->b_flags & B_READ)) {
   1303 			bcopy(fd->sc_copybuf
   1304 			      + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
   1305 			      bp->b_data + fd->sc_skip,
   1306 			      FDC_BSIZE);
   1307 			fdc->sc_state = IOCOMPLETE;
   1308 			goto iocomplete2;
   1309 		} else {
   1310 			bcopy(bp->b_data + fd->sc_skip,
   1311 			      fd->sc_copybuf
   1312 			      + (fd->sc_part & SEC_P01 ? FDC_BSIZE : 0),
   1313 			      FDC_BSIZE);
   1314 			fdc_dmastart(fdc, read, fd->sc_copybuf, 1024);
   1315 		}
   1316 		out_fdc(iot, ioh, NE7CMD_WRITE);	/* WRITE */
   1317 		out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
   1318 		out_fdc(iot, ioh, bp->b_cylinder);	/* cylinder */
   1319 		out_fdc(iot, ioh, head);
   1320 		out_fdc(iot, ioh, sec + 1);		/* sector +1 */
   1321 		out_fdc(iot, ioh, fd->sc_type->secsize); /* sector size */
   1322 		out_fdc(iot, ioh, sectrac);		/* sectors/track */
   1323 		out_fdc(iot, ioh, fd->sc_type->gap1);	/* gap1 size */
   1324 		out_fdc(iot, ioh, fd->sc_type->datalen); /* data length */
   1325 		fdc->sc_state = IOCOMPLETE;
   1326 		/* allow 2 seconds for operation */
   1327 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1328 		return 1;				/* will return later */
   1329 
   1330 	case SEEKWAIT:
   1331 		callout_stop(&fdc->sc_timo_ch);
   1332 		fdc->sc_state = SEEKCOMPLETE;
   1333 		/* allow 1/50 second for heads to settle */
   1334 #if 0
   1335 		callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
   1336 #endif
   1337 		return 1;
   1338 
   1339 	case SEEKCOMPLETE:
   1340 		/* Make sure seek really happened */
   1341 		DPRINTF(("fdcintr: SEEKCOMPLETE: FDC status = %x\n",
   1342 			 bus_space_read_1(fdc->sc_iot, fdc->sc_ioh, fdsts)));
   1343 		out_fdc(iot, ioh, NE7CMD_SENSEI);
   1344 		tmp = fdcresult(fdc);
   1345 		if ((st0 & 0xf8) == 0xc0) {
   1346 			DPRINTF(("fdcintr: first seek!\n"));
   1347 			fdc->sc_state = DORECAL;
   1348 			goto loop;
   1349 		} else if (tmp != 2 ||
   1350 			   (st0 & 0xf8) != 0x20 ||
   1351 			   cyl != bp->b_cylinder) {
   1352 #ifdef FDDEBUG
   1353 			fdcstatus(&fd->sc_dev, 2, "seek failed");
   1354 #endif
   1355 			fdcretry(fdc);
   1356 			goto loop;
   1357 		}
   1358 		fd->sc_cylin = bp->b_cylinder;
   1359 		goto doio;
   1360 
   1361 	case IOTIMEDOUT:
   1362 #if 0
   1363 		isa_dmaabort(fdc->sc_drq);
   1364 #endif
   1365 	case SEEKTIMEDOUT:
   1366 	case RECALTIMEDOUT:
   1367 	case RESETTIMEDOUT:
   1368 		fdcretry(fdc);
   1369 		goto loop;
   1370 
   1371 	case IOCOMPLETE: /* IO DONE, post-analyze */
   1372 		callout_stop(&fdc->sc_timo_ch);
   1373 		DPRINTF(("fdcintr: in IOCOMPLETE\n"));
   1374 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
   1375 			printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
   1376 #if 0
   1377 			isa_dmaabort(fdc->sc_drq);
   1378 #endif
   1379 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
   1380 				  "read failed" : "write failed");
   1381 			printf("blkno %d nblks %d\n",
   1382 			    fd->sc_blkno, fd->sc_nblks);
   1383 			fdcretry(fdc);
   1384 			goto loop;
   1385 		}
   1386 #if 0
   1387 		isa_dmadone(bp->b_flags & B_READ, bp->b_data + fd->sc_skip,
   1388 		    nblks * FDC_BSIZE, fdc->sc_drq);
   1389 #endif
   1390 	iocomplete2:
   1391 		if (fdc->sc_errors) {
   1392 			diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
   1393 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
   1394 			printf("\n");
   1395 			fdc->sc_errors = 0;
   1396 		}
   1397 		fd->sc_blkno += fd->sc_nblks;
   1398 		fd->sc_skip += fd->sc_nbytes;
   1399 		fd->sc_bcount -= fd->sc_nbytes;
   1400 		DPRINTF(("fd->sc_bcount = %d\n", fd->sc_bcount));
   1401 		if (fd->sc_bcount > 0) {
   1402 			bp->b_cylinder = fd->sc_blkno
   1403 				/ (fd->sc_type->seccyl
   1404 				   * (1 << (fd->sc_type->secsize - 2)));
   1405 			goto doseek;
   1406 		}
   1407 		fdfinish(fd, bp);
   1408 		goto loop;
   1409 
   1410 	case COPYCOMPLETE: /* IO DONE, post-analyze */
   1411 		DPRINTF(("fdcintr: COPYCOMPLETE:"));
   1412 		callout_stop(&fdc->sc_timo_ch);
   1413 		if ((tmp = fdcresult(fdc)) != 7 || (st0 & 0xf8) != 0) {
   1414 			printf("fdcintr: resnum=%d, st0=%x\n", tmp, st0);
   1415 #if 0
   1416 			isa_dmaabort(fdc->sc_drq);
   1417 #endif
   1418 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
   1419 				  "read failed" : "write failed");
   1420 			printf("blkno %d nblks %d\n",
   1421 			    fd->sc_blkno, fd->sc_nblks);
   1422 			fdcretry(fdc);
   1423 			goto loop;
   1424 		}
   1425 		goto doiohalf;
   1426 
   1427 	case DORESET:
   1428 		DPRINTF(("fdcintr: in DORESET\n"));
   1429 		/* try a reset, keep motor on */
   1430 		fd_set_motor(fdc, 1);
   1431 		DELAY(100);
   1432 		fd_set_motor(fdc, 0);
   1433 		fdc->sc_state = RESETCOMPLETE;
   1434 		callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
   1435 		return 1;			/* will return later */
   1436 
   1437 	case RESETCOMPLETE:
   1438 		DPRINTF(("fdcintr: in RESETCOMPLETE\n"));
   1439 		callout_stop(&fdc->sc_timo_ch);
   1440 		/* clear the controller output buffer */
   1441 		for (i = 0; i < 4; i++) {
   1442 			out_fdc(iot, ioh, NE7CMD_SENSEI);
   1443 			(void) fdcresult(fdc);
   1444 		}
   1445 
   1446 		/* fall through */
   1447 	case DORECAL:
   1448 		DPRINTF(("fdcintr: in DORECAL\n"));
   1449 		out_fdc(iot, ioh, NE7CMD_RECAL);	/* recalibrate function */
   1450 		out_fdc(iot, ioh, fd->sc_drive);
   1451 		fdc->sc_state = RECALWAIT;
   1452 		callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
   1453 		return 1;			/* will return later */
   1454 
   1455 	case RECALWAIT:
   1456 		DPRINTF(("fdcintr: in RECALWAIT\n"));
   1457 		callout_stop(&fdc->sc_timo_ch);
   1458 		fdc->sc_state = RECALCOMPLETE;
   1459 		/* allow 1/30 second for heads to settle */
   1460 #if 0
   1461 		callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
   1462 #endif
   1463 		return 1;			/* will return later */
   1464 
   1465 	case RECALCOMPLETE:
   1466 		DPRINTF(("fdcintr: in RECALCOMPLETE\n"));
   1467 		out_fdc(iot, ioh, NE7CMD_SENSEI);
   1468 		tmp = fdcresult(fdc);
   1469 		if ((st0 & 0xf8) == 0xc0) {
   1470 			DPRINTF(("fdcintr: first seek!\n"));
   1471 			fdc->sc_state = DORECAL;
   1472 			goto loop;
   1473 		} else if (tmp != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
   1474 #ifdef FDDEBUG
   1475 			fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
   1476 #endif
   1477 			fdcretry(fdc);
   1478 			goto loop;
   1479 		}
   1480 		fd->sc_cylin = 0;
   1481 		goto doseek;
   1482 
   1483 	case MOTORWAIT:
   1484 		if (fd->sc_flags & FD_MOTOR_WAIT)
   1485 			return 1;		/* time's not up yet */
   1486 		goto doseek;
   1487 
   1488 	default:
   1489 		fdcstatus(&fd->sc_dev, 0, "stray interrupt");
   1490 		return 1;
   1491 	}
   1492 #ifdef DIAGNOSTIC
   1493 	panic("fdcintr: impossible");
   1494 #endif
   1495 #undef	st0
   1496 #undef	cyl
   1497 }
   1498 
   1499 void
   1500 fdcretry(fdc)
   1501 	struct fdc_softc *fdc;
   1502 {
   1503 	struct fd_softc *fd;
   1504 	struct buf *bp;
   1505 	char bits[64];
   1506 
   1507 	DPRINTF(("fdcretry:\n"));
   1508 	fd = fdc->sc_drives.tqh_first;
   1509 	bp = BUFQ_FIRST(&fd->sc_q);
   1510 
   1511 	switch (fdc->sc_errors) {
   1512 	case 0:
   1513 		/* try again */
   1514 		fdc->sc_state = SEEKCOMPLETE;
   1515 		break;
   1516 
   1517 	case 1: case 2: case 3:
   1518 		/* didn't work; try recalibrating */
   1519 		fdc->sc_state = DORECAL;
   1520 		break;
   1521 
   1522 	case 4:
   1523 		/* still no go; reset the bastard */
   1524 		fdc->sc_state = DORESET;
   1525 		break;
   1526 
   1527 	default:
   1528 		diskerr(bp, "fd", "hard error", LOG_PRINTF,
   1529 			fd->sc_skip, (struct disklabel *)NULL);
   1530 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
   1531 						    NE7_ST0BITS, bits,
   1532 						    sizeof(bits)));
   1533 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
   1534 						   NE7_ST1BITS, bits,
   1535 						   sizeof(bits)));
   1536 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
   1537 						   NE7_ST2BITS, bits,
   1538 						   sizeof(bits)));
   1539 		printf(" cyl %d head %d sec %d)\n",
   1540 		       fdc->sc_status[3],
   1541 		       fdc->sc_status[4],
   1542 		       fdc->sc_status[5]);
   1543 
   1544 		bp->b_flags |= B_ERROR;
   1545 		bp->b_error = EIO;
   1546 		fdfinish(fd, bp);
   1547 	}
   1548 	fdc->sc_errors++;
   1549 }
   1550 
   1551 int
   1552 fdsize(dev)
   1553 	dev_t dev;
   1554 {
   1555 
   1556 	/* Swapping to floppies would not make sense. */
   1557 	return -1;
   1558 }
   1559 
   1560 int
   1561 fddump(dev, blkno, va, size)
   1562 	dev_t dev;
   1563 	daddr_t blkno;
   1564 	caddr_t va;
   1565 	size_t size;
   1566 {
   1567 
   1568 	/* Not implemented. */
   1569 	return ENXIO;
   1570 }
   1571 
   1572 int
   1573 fdioctl(devvp, cmd, addr, flag, p)
   1574 	struct vnode *devvp;
   1575 	u_long cmd;
   1576 	caddr_t addr;
   1577 	int flag;
   1578 	struct proc *p;
   1579 {
   1580 	struct fd_softc *fd = vdev_privdata(devvp);
   1581 	struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
   1582 	dev_t dev = vdev_rdev(devvp);
   1583 	int unit = FDUNIT(dev);
   1584 	int part = DISKPART(dev);
   1585 	struct disklabel buffer;
   1586 	int error;
   1587 
   1588 	DPRINTF(("fdioctl:\n"));
   1589 	switch (cmd) {
   1590 	case DIOCGDINFO:
   1591 #if 1
   1592 		*(struct disklabel *)addr = *(fd->sc_dk.dk_label);
   1593 		return(0);
   1594 #else
   1595 		memset(&buffer, 0, sizeof(buffer));
   1596 
   1597 		buffer.d_secpercyl = fd->sc_type->seccyl;
   1598 		buffer.d_type = DTYPE_FLOPPY;
   1599 		buffer.d_secsize = 128 << fd->sc_type->secsize;
   1600 
   1601 		if (readdisklabel(devvp, fdstrategy, &buffer, NULL) != NULL)
   1602 			return EINVAL;
   1603 
   1604 		*(struct disklabel *)addr = buffer;
   1605 		return 0;
   1606 #endif
   1607 
   1608 	case DIOCGPART:
   1609 		((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
   1610 		((struct partinfo *)addr)->part =
   1611 		    &fd->sc_dk.dk_label->d_partitions[part];
   1612 		return(0);
   1613 
   1614 	case DIOCWLABEL:
   1615 		if ((flag & FWRITE) == 0)
   1616 			return EBADF;
   1617 		/* XXX do something */
   1618 		return 0;
   1619 
   1620 	case DIOCWDINFO:
   1621 		if ((flag & FWRITE) == 0)
   1622 			return EBADF;
   1623 
   1624 		error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
   1625 		if (error)
   1626 			return error;
   1627 
   1628 		error = writedisklabel(devvp, fdstrategy, &buffer, NULL);
   1629 		return error;
   1630 
   1631 	case DIOCLOCK:
   1632 		/*
   1633 		 * Nothing to do here, really.
   1634 		 */
   1635 		return 0; /* XXX */
   1636 
   1637 	case DIOCEJECT:
   1638 		if (*(int *)addr == 0) {
   1639 			/*
   1640 			 * Don't force eject: check that we are the only
   1641 			 * partition open. If so, unlock it.
   1642 			 */
   1643 			if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 ||
   1644 			    fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask !=
   1645 			    fd->sc_dk.dk_openmask) {
   1646 				return (EBUSY);
   1647 			}
   1648 		}
   1649 		/* FALLTHROUGH */
   1650 	case ODIOCEJECT:
   1651 		fd_do_eject(fdc, unit);
   1652 		return 0;
   1653 
   1654 	default:
   1655 		return ENOTTY;
   1656 	}
   1657 
   1658 #ifdef DIAGNOSTIC
   1659 	panic("fdioctl: impossible");
   1660 #endif
   1661 }
   1662 
   1663 void
   1664 fd_do_eject(fdc, unit)
   1665 	struct fdc_softc *fdc;
   1666 	int unit;
   1667 {
   1668 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout,
   1669 			  0x20 | ( 1 << unit));
   1670 	DELAY(1); /* XXX */
   1671 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, 0x20);
   1672 }
   1673 
   1674 /*
   1675  * Build disk label. For now we only create a label from what we know
   1676  * from 'sc'.
   1677  */
   1678 static int
   1679 fdgetdisklabel(sc, devvp)
   1680 	struct fd_softc *sc;
   1681 	struct vnode *devvp;
   1682 {
   1683 	struct disklabel *lp;
   1684 	int part;
   1685 
   1686 	DPRINTF(("fdgetdisklabel()\n"));
   1687 
   1688 	part = DISKPART(vdev_rdev(devvp));
   1689 	lp = sc->sc_dk.dk_label;
   1690 	bzero(lp, sizeof(struct disklabel));
   1691 
   1692 	lp->d_secsize     = 128 << sc->sc_type->secsize;
   1693 	lp->d_ntracks     = sc->sc_type->heads;
   1694 	lp->d_nsectors    = sc->sc_type->sectrac;
   1695 	lp->d_secpercyl   = lp->d_ntracks * lp->d_nsectors;
   1696 	lp->d_ncylinders  = sc->sc_type->size / lp->d_secpercyl;
   1697 	lp->d_secperunit  = sc->sc_type->size;
   1698 
   1699 	lp->d_type        = DTYPE_FLOPPY;
   1700 	lp->d_rpm         = 300; 	/* XXX */
   1701 	lp->d_interleave  = 1;		/* FIXME: is this OK?		*/
   1702 	lp->d_bbsize      = 0;
   1703 	lp->d_sbsize      = 0;
   1704 	lp->d_npartitions = part + 1;
   1705 #define STEP_DELAY	6000	/* 6ms (6000us) delay after stepping	*/
   1706 	lp->d_trkseek     = STEP_DELAY; /* XXX */
   1707 	lp->d_magic       = DISKMAGIC;
   1708 	lp->d_magic2      = DISKMAGIC;
   1709 	lp->d_checksum    = dkcksum(lp);
   1710 	lp->d_partitions[part].p_size   = lp->d_secperunit;
   1711 	lp->d_partitions[part].p_fstype = FS_UNUSED;
   1712 	lp->d_partitions[part].p_fsize  = 1024;
   1713 	lp->d_partitions[part].p_frag   = 8;
   1714 
   1715 	return(0);
   1716 }
   1717 
   1718 #include <dev/cons.h>
   1719 
   1720 /*
   1721  * Mountroot hook: prompt the user to enter the root file system
   1722  * floppy.
   1723  */
   1724 void
   1725 fd_mountroot_hook(dev)
   1726 	struct device *dev;
   1727 {
   1728 	struct fd_softc *fd = (void*) dev;
   1729 	struct fdc_softc *fdc = (void*) fd->sc_dev.dv_parent;
   1730 	int c;
   1731 
   1732 	fd_do_eject(fdc, dev->dv_unit);
   1733 	printf("Insert filesystem floppy and press return.");
   1734 	for (;;) {
   1735 		c = cngetc();
   1736 		if ((c == '\r') || (c == '\n')) {
   1737 			printf("\n");
   1738 			break;
   1739 		}
   1740 	}
   1741 }
   1742