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