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