Home | History | Annotate | Line # | Download | only in dev
fd.c revision 1.62
      1 /*	$NetBSD: fd.c,v 1.62 2004/10/28 07:07:39 yamt 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.62 2004/10/28 07:07:39 yamt 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/bufq.h>
     94 #include <sys/uio.h>
     95 #include <sys/syslog.h>
     96 #include <sys/queue.h>
     97 #include <sys/fdio.h>
     98 #if NRND > 0
     99 #include <sys/rnd.h>
    100 #endif
    101 
    102 #include <uvm/uvm_extern.h>
    103 
    104 #include <machine/bus.h>
    105 #include <machine/cpu.h>
    106 
    107 #include <arch/x68k/dev/intiovar.h>
    108 #include <arch/x68k/dev/dmacvar.h>
    109 #include <arch/x68k/dev/fdreg.h>
    110 #include <arch/x68k/dev/opmvar.h> /* for CT1 access */
    111 
    112 #include "locators.h"
    113 
    114 #ifdef FDDEBUG
    115 #define DPRINTF(x)      if (fddebug) printf x
    116 int     fddebug = 0;
    117 #else
    118 #define DPRINTF(x)
    119 #endif
    120 
    121 #define FDUNIT(dev)	(minor(dev) / 8)
    122 #define FDTYPE(dev)	(minor(dev) % 8)
    123 
    124 enum fdc_state {
    125 	DEVIDLE = 0,
    126 	MOTORWAIT,
    127 	DOSEEK,
    128 	SEEKWAIT,
    129 	SEEKTIMEDOUT,
    130 	SEEKCOMPLETE,
    131 	DOIO,
    132 	IOCOMPLETE,
    133 	IOTIMEDOUT,
    134 	DORESET,
    135 	RESETCOMPLETE,
    136 	RESETTIMEDOUT,
    137 	DORECAL,
    138 	RECALWAIT,
    139 	RECALTIMEDOUT,
    140 	RECALCOMPLETE,
    141 	DOCOPY,
    142 	DOIOHALF,
    143 	COPYCOMPLETE,
    144 };
    145 
    146 /* software state, per controller */
    147 struct fdc_softc {
    148 	struct device sc_dev;		/* boilerplate */
    149 
    150 	bus_space_tag_t sc_iot;		/* intio i/o space identifier */
    151 	bus_space_handle_t sc_ioh;	/* intio io handle */
    152 
    153 	struct callout sc_timo_ch;	/* timeout callout */
    154 	struct callout sc_intr_ch;	/* pseudo-intr callout */
    155 
    156 	bus_dma_tag_t sc_dmat;		/* intio DMA tag */
    157 	bus_dmamap_t sc_dmamap;		/* DMA map */
    158 	u_int8_t *sc_addr;			/* physical address */
    159 	struct dmac_channel_stat *sc_dmachan; /* intio DMA channel */
    160 	struct dmac_dma_xfer *sc_xfer;	/* DMA transfer */
    161 
    162 	struct fd_softc *sc_fd[4];	/* pointers to children */
    163 	TAILQ_HEAD(drivehead, fd_softc) sc_drives;
    164 	enum fdc_state sc_state;
    165 	int sc_errors;			/* number of retries so far */
    166 	u_char sc_status[7];		/* copy of registers */
    167 } fdc_softc;
    168 
    169 int fdcintr __P((void*));
    170 void fdcreset __P((struct fdc_softc *));
    171 
    172 /* controller driver configuration */
    173 int fdcprobe __P((struct device *, struct cfdata *, void *));
    174 void fdcattach __P((struct device *, struct device *, void *));
    175 int fdprint __P((void *, const char *));
    176 
    177 CFATTACH_DECL(fdc, sizeof(struct fdc_softc),
    178     fdcprobe, fdcattach, NULL, NULL);
    179 
    180 extern struct cfdriver fdc_cd;
    181 
    182 /*
    183  * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
    184  * we tell them apart.
    185  */
    186 struct fd_type {
    187 	int	sectrac;	/* sectors per track */
    188 	int	heads;		/* number of heads */
    189 	int	seccyl;		/* sectors per cylinder */
    190 	int	secsize;	/* size code for sectors */
    191 	int	datalen;	/* data len when secsize = 0 */
    192 	int	steprate;	/* step rate and head unload time */
    193 	int	gap1;		/* gap len between sectors */
    194 	int	gap2;		/* formatting gap */
    195 	int	cyls;		/* total num of cylinders */
    196 	int	size;		/* size of disk in sectors */
    197 	int	step;		/* steps per cylinder */
    198 	int	rate;		/* transfer speed code */
    199 	char	*name;
    200 };
    201 
    202 /* The order of entries in the following table is important -- BEWARE! */
    203 struct fd_type fd_types[] = {
    204         {  8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS, "1.2MB/[1024bytes/sector]"    }, /* 1.2 MB japanese format */
    205         { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB"    }, /* 1.44MB diskette */
    206         { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB"    }, /* 1.2 MB AT-diskettes */
    207         {  9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */
    208         {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
    209         {  9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB"    }, /* 3.5" 720kB diskette */
    210         {  9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x"  }, /* 720kB in 1.2MB drive */
    211         {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x"  }, /* 360kB in 720kB drive */
    212 };
    213 
    214 /* software state, per disk (with up to 4 disks per ctlr) */
    215 struct fd_softc {
    216 	struct device sc_dev;
    217 	struct disk sc_dk;
    218 
    219 	struct fd_type *sc_deftype;	/* default type descriptor */
    220 	struct fd_type *sc_type;	/* current type descriptor */
    221 
    222 	struct callout sc_motoron_ch;
    223 	struct callout sc_motoroff_ch;
    224 
    225 	daddr_t	sc_blkno;	/* starting block number */
    226 	int sc_bcount;		/* byte count left */
    227  	int sc_opts;			/* user-set options */
    228 	int sc_skip;		/* bytes already transferred */
    229 	int sc_nblks;		/* number of blocks currently transferring */
    230 	int sc_nbytes;		/* number of bytes currently transferring */
    231 
    232 	int sc_drive;		/* physical unit number */
    233 	int sc_flags;
    234 #define	FD_BOPEN	0x01		/* it's open */
    235 #define	FD_COPEN	0x02		/* it's open */
    236 #define	FD_OPEN		(FD_BOPEN|FD_COPEN)	/* it's open */
    237 #define	FD_MOTOR	0x04		/* motor should be on */
    238 #define	FD_MOTOR_WAIT	0x08		/* motor coming up */
    239 #define	FD_ALIVE	0x10		/* alive */
    240 	int sc_cylin;		/* where we think the head is */
    241 
    242 	TAILQ_ENTRY(fd_softc) sc_drivechain;
    243 	int sc_ops;		/* I/O ops since last switch */
    244 	struct bufq_state sc_q;	/* pending I/O requests */
    245 	int sc_active;		/* number of active I/O operations */
    246 	u_char *sc_copybuf;	/* for secsize >=3 */
    247 	u_char sc_part;		/* for secsize >=3 */
    248 #define	SEC_P10	0x02		/* first part */
    249 #define	SEC_P01	0x01		/* second part */
    250 #define	SEC_P11	0x03		/* both part */
    251 
    252 #if NRND > 0
    253 	rndsource_element_t	rnd_source;
    254 #endif
    255 };
    256 
    257 /* floppy driver configuration */
    258 int fdprobe __P((struct device *, struct cfdata *, void *));
    259 void fdattach __P((struct device *, struct device *, void *));
    260 
    261 CFATTACH_DECL(fd, sizeof(struct fd_softc),
    262     fdprobe, fdattach, NULL, NULL);
    263 
    264 extern struct cfdriver fd_cd;
    265 
    266 dev_type_open(fdopen);
    267 dev_type_close(fdclose);
    268 dev_type_read(fdread);
    269 dev_type_write(fdwrite);
    270 dev_type_ioctl(fdioctl);
    271 dev_type_strategy(fdstrategy);
    272 
    273 const struct bdevsw fd_bdevsw = {
    274 	fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK
    275 };
    276 
    277 const struct cdevsw fd_cdevsw = {
    278 	fdopen, fdclose, fdread, fdwrite, fdioctl,
    279 	nostop, notty, nopoll, nommap, nokqfilter, D_DISK
    280 };
    281 
    282 void fdstart __P((struct fd_softc *fd));
    283 
    284 struct dkdriver fddkdriver = { fdstrategy };
    285 
    286 void fd_set_motor __P((struct fdc_softc *fdc, int reset));
    287 void fd_motor_off __P((void *arg));
    288 void fd_motor_on __P((void *arg));
    289 int fdcresult __P((struct fdc_softc *fdc));
    290 int out_fdc __P((bus_space_tag_t, bus_space_handle_t, u_char x));
    291 void fdcstart __P((struct fdc_softc *fdc));
    292 void fdcstatus __P((struct device *dv, int n, char *s));
    293 void fdctimeout __P((void *arg));
    294 void fdcpseudointr __P((void *arg));
    295 void fdcretry __P((struct fdc_softc *fdc));
    296 void fdfinish __P((struct fd_softc *fd, struct buf *bp));
    297 __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
    298 static int fdcpoll __P((struct fdc_softc *));
    299 static int fdgetdisklabel __P((struct fd_softc *, dev_t));
    300 static void fd_do_eject __P((struct fdc_softc *, int));
    301 
    302 void fd_mountroot_hook __P((struct device *));
    303 
    304 /* DMA transfer routines */
    305 __inline static void fdc_dmastart __P((struct fdc_softc*, int,
    306 				       caddr_t, vsize_t));
    307 static int fdcdmaintr __P((void*));
    308 static int fdcdmaerrintr __P((void*));
    309 
    310 __inline static void
    311 fdc_dmastart(fdc, read, addr, count)
    312 	struct fdc_softc *fdc;
    313 	int read;
    314 	caddr_t addr;
    315 	vsize_t count;
    316 {
    317 	int error;
    318 
    319 	DPRINTF(("fdc_dmastart: %s, addr = %p, count = %ld\n",
    320 		 read ? "read" : "write", (caddr_t) addr, count));
    321 
    322 	error = bus_dmamap_load(fdc->sc_dmat, fdc->sc_dmamap, addr, count,
    323 				0, BUS_DMA_NOWAIT);
    324 	if (error) {
    325 		panic ("fdc_dmastart: cannot load dmamap");
    326 	}
    327 
    328 	bus_dmamap_sync(fdc->sc_dmat, fdc->sc_dmamap, 0, count,
    329 			read?BUS_DMASYNC_PREREAD:BUS_DMASYNC_PREWRITE);
    330 
    331 	fdc->sc_xfer = dmac_prepare_xfer(fdc->sc_dmachan, fdc->sc_dmat,
    332 					 fdc->sc_dmamap,
    333 					 (read?
    334 					  DMAC_OCR_DIR_DTM:DMAC_OCR_DIR_MTD),
    335 					 (DMAC_SCR_MAC_COUNT_UP|
    336 					  DMAC_SCR_DAC_NO_COUNT),
    337 					 (u_int8_t*) (fdc->sc_addr +
    338 						      fddata));	/* XXX */
    339 
    340 	dmac_start_xfer(fdc->sc_dmachan->ch_softc, fdc->sc_xfer);
    341 }
    342 
    343 static int
    344 fdcdmaintr(arg)
    345 	void *arg;
    346 {
    347 	struct fdc_softc *fdc = arg;
    348 
    349 	bus_dmamap_unload(fdc->sc_dmat, fdc->sc_dmamap);
    350 
    351 	return 0;
    352 }
    353 
    354 static int
    355 fdcdmaerrintr(dummy)
    356 	void *dummy;
    357 {
    358 	DPRINTF(("fdcdmaerrintr\n"));
    359 
    360 	return 0;
    361 }
    362 
    363 /* ARGSUSED */
    364 int
    365 fdcprobe(parent, cf, aux)
    366 	struct device *parent;
    367 	struct cfdata *cf;
    368 	void *aux;
    369 {
    370 	struct intio_attach_args *ia = aux;
    371 
    372 	if (strcmp(ia->ia_name, "fdc") != 0)
    373 		return 0;
    374 
    375 	if (ia->ia_addr == INTIOCF_ADDR_DEFAULT)
    376 		ia->ia_addr = FDC_ADDR;
    377 	if (ia->ia_intr == INTIOCF_INTR_DEFAULT)
    378 		ia->ia_intr = FDC_INTR;
    379 	if (ia->ia_dma == INTIOCF_DMA_DEFAULT)
    380 		ia->ia_dma = FDC_DMA;
    381 	if (ia->ia_dmaintr == INTIOCF_DMAINTR_DEFAULT)
    382 		ia->ia_dmaintr = FDC_DMAINTR;
    383 
    384 	if ((ia->ia_intr & 0x03) != 0)
    385 		return 0;
    386 
    387 	ia->ia_size = 0x2000;
    388 	if (intio_map_allocate_region (parent, ia, INTIO_MAP_TESTONLY))
    389 		return 0;
    390 
    391 	/* builtin device; always there */
    392 	return 1;
    393 }
    394 
    395 /*
    396  * Arguments passed between fdcattach and fdprobe.
    397  */
    398 struct fdc_attach_args {
    399 	int fa_drive;
    400 	struct fd_type *fa_deftype;
    401 };
    402 
    403 /*
    404  * Print the location of a disk drive (called just before attaching the
    405  * the drive).  If `fdc' is not NULL, the drive was found but was not
    406  * in the system config file; print the drive name as well.
    407  * Return QUIET (config_find ignores this if the device was configured) to
    408  * avoid printing `fdN not configured' messages.
    409  */
    410 int
    411 fdprint(aux, fdc)
    412 	void *aux;
    413 	const char *fdc;
    414 {
    415 	register struct fdc_attach_args *fa = aux;
    416 
    417 	if (!fdc)
    418 		aprint_normal(" drive %d", fa->fa_drive);
    419 	return QUIET;
    420 }
    421 
    422 void
    423 fdcattach(parent, self, aux)
    424 	struct device *parent, *self;
    425 	void *aux;
    426 {
    427 	struct fdc_softc *fdc = (void *)self;
    428 	bus_space_tag_t iot;
    429 	bus_space_handle_t ioh;
    430 	struct intio_attach_args *ia = aux;
    431 	struct fdc_attach_args fa;
    432 
    433 	iot = ia->ia_bst;
    434 
    435 	printf("\n");
    436 
    437 	callout_init(&fdc->sc_timo_ch);
    438 	callout_init(&fdc->sc_intr_ch);
    439 
    440 	/* Re-map the I/O space. */
    441 	bus_space_map(iot, ia->ia_addr, 0x2000, BUS_SPACE_MAP_SHIFTED, &ioh);
    442 
    443 	fdc->sc_iot = iot;
    444 	fdc->sc_ioh = ioh;
    445 	fdc->sc_addr = (void*) ia->ia_addr;
    446 
    447 	fdc->sc_dmat = ia->ia_dmat;
    448 	fdc->sc_state = DEVIDLE;
    449 	TAILQ_INIT(&fdc->sc_drives);
    450 
    451 	/* Initialize DMAC channel */
    452 	fdc->sc_dmachan = dmac_alloc_channel(parent, ia->ia_dma, "fdc",
    453 					     ia->ia_dmaintr, fdcdmaintr, fdc,
    454 					     ia->ia_dmaintr+1, fdcdmaerrintr,
    455 					     fdc);
    456 	if (bus_dmamap_create(fdc->sc_dmat, FDC_MAXIOSIZE, 1, DMAC_MAXSEGSZ,
    457 			      0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
    458 			      &fdc->sc_dmamap)) {
    459 		printf("%s: can't set up intio DMA map\n",
    460 		    fdc->sc_dev.dv_xname);
    461 		return;
    462 	}
    463 
    464 	if (intio_intr_establish(ia->ia_intr, "fdc", fdcintr, fdc))
    465 		panic ("Could not establish interrupt (duplicated vector?).");
    466 	intio_set_ivec(ia->ia_intr);
    467 
    468 	/* reset */
    469 	intio_disable_intr(SICILIAN_INTR_FDD);
    470 	intio_enable_intr(SICILIAN_INTR_FDC);
    471 	fdcresult(fdc);
    472 	fdcreset(fdc);
    473 
    474 	printf("%s: uPD72065 FDC\n", fdc->sc_dev.dv_xname);
    475 	out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
    476 	out_fdc(iot, ioh, 0xd0);
    477 	out_fdc(iot, ioh, 0x10);
    478 
    479 	/* physical limit: four drives per controller. */
    480 	for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
    481 		(void)config_found(self, (void *)&fa, fdprint);
    482 	}
    483 
    484 	intio_enable_intr(SICILIAN_INTR_FDC);
    485 }
    486 
    487 void
    488 fdcreset(fdc)
    489 	struct fdc_softc *fdc;
    490 {
    491 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdsts, NE7CMD_RESET);
    492 }
    493 
    494 static int
    495 fdcpoll(fdc)
    496 	struct fdc_softc *fdc;
    497 {
    498 	int i = 25000, n;
    499 	while (--i > 0) {
    500 		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
    501 			out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
    502 			n = fdcresult(fdc);
    503 			break;
    504 		}
    505 		DELAY(100);
    506 	}
    507 	return i;
    508 }
    509 
    510 int
    511 fdprobe(parent, cf, aux)
    512 	struct device *parent;
    513 	struct cfdata *cf;
    514 	void *aux;
    515 {
    516 	struct fdc_softc *fdc = (void *)parent;
    517 	struct fd_type *type;
    518 	struct fdc_attach_args *fa = aux;
    519 	int drive = fa->fa_drive;
    520 	bus_space_tag_t iot = fdc->sc_iot;
    521 	bus_space_handle_t ioh = fdc->sc_ioh;
    522 	int n = 0;
    523 	int found = 0;
    524 	int i;
    525 
    526 	if (cf->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
    527 	    cf->cf_loc[FDCCF_UNIT] != drive)
    528 		return 0;
    529 
    530 	type = &fd_types[0];	/* XXX 1.2MB */
    531 
    532 	intio_disable_intr(SICILIAN_INTR_FDC);
    533 
    534 	/* select drive and turn on motor */
    535 	bus_space_write_1(iot, ioh, fdctl, 0x80 | (type->rate << 4)| drive);
    536 	fdc_force_ready(FDCRDY);
    537 	fdcpoll(fdc);
    538 
    539 retry:
    540 	out_fdc(iot, ioh, NE7CMD_RECAL);
    541 	out_fdc(iot, ioh, drive);
    542 
    543 	i = 25000;
    544 	while (--i > 0) {
    545 		if ((intio_get_sicilian_intr() & SICILIAN_STAT_FDC)) {
    546 			out_fdc(iot, ioh, NE7CMD_SENSEI);
    547 			n = fdcresult(fdc);
    548 			break;
    549 		}
    550 		DELAY(100);
    551 	}
    552 
    553 #ifdef FDDEBUG
    554 	{
    555 		int i;
    556 		DPRINTF(("fdprobe: status"));
    557 		for (i = 0; i < n; i++)
    558 			DPRINTF((" %x", fdc->sc_status[i]));
    559 		DPRINTF(("\n"));
    560 	}
    561 #endif
    562 
    563 	if (n == 2) {
    564 		if ((fdc->sc_status[0] & 0xf0) == 0x20)
    565 			found = 1;
    566 		else if ((fdc->sc_status[0] & 0xf0) == 0xc0)
    567 			goto retry;
    568 	}
    569 
    570 	/* turn off motor */
    571 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh,
    572 			  fdctl, (type->rate << 4)| drive);
    573 	fdc_force_ready(FDCSTBY);
    574 	if (!found) {
    575 		intio_enable_intr(SICILIAN_INTR_FDC);
    576 		return 0;
    577 	}
    578 
    579 	return 1;
    580 }
    581 
    582 /*
    583  * Controller is working, and drive responded.  Attach it.
    584  */
    585 void
    586 fdattach(parent, self, aux)
    587 	struct device *parent, *self;
    588 	void *aux;
    589 {
    590 	struct fdc_softc *fdc = (void *)parent;
    591 	struct fd_softc *fd = (void *)self;
    592 	struct fdc_attach_args *fa = aux;
    593 	struct fd_type *type = &fd_types[0];	/* XXX 1.2MB */
    594 	int drive = fa->fa_drive;
    595 
    596 	callout_init(&fd->sc_motoron_ch);
    597 	callout_init(&fd->sc_motoroff_ch);
    598 
    599 	fd->sc_flags = 0;
    600 
    601 	if (type)
    602 		printf(": %s, %d cyl, %d head, %d sec\n", type->name,
    603 		       type->cyls, type->heads, type->sectrac);
    604 	else
    605 		printf(": density unknown\n");
    606 
    607 	bufq_alloc(&fd->sc_q, BUFQ_DISKSORT|BUFQ_SORT_CYLINDER);
    608 	fd->sc_cylin = -1;
    609 	fd->sc_drive = drive;
    610 	fd->sc_deftype = type;
    611 	fdc->sc_fd[drive] = fd;
    612 
    613 	fd->sc_copybuf = (u_char *)malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK);
    614 	if (fd->sc_copybuf == 0)
    615 		printf("fdprobe: WARNING!! malloc() failed.\n");
    616 	fd->sc_flags |= FD_ALIVE;
    617 
    618 	/*
    619 	 * Initialize and attach the disk structure.
    620 	 */
    621 	fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
    622 	fd->sc_dk.dk_driver = &fddkdriver;
    623 	disk_attach(&fd->sc_dk);
    624 
    625 	/*
    626 	 * Establish a mountroot_hook anyway in case we booted
    627 	 * with RB_ASKNAME and get selected as the boot device.
    628 	 */
    629 	mountroothook_establish(fd_mountroot_hook, &fd->sc_dev);
    630 
    631 #if NRND > 0
    632 	rnd_attach_source(&fd->rnd_source, fd->sc_dev.dv_xname,
    633 			  RND_TYPE_DISK, 0);
    634 #endif
    635 }
    636 
    637 __inline struct fd_type *
    638 fd_dev_to_type(fd, dev)
    639 	struct fd_softc *fd;
    640 	dev_t dev;
    641 {
    642 	int type = FDTYPE(dev);
    643 
    644 	if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
    645 		return NULL;
    646 	return &fd_types[type];
    647 }
    648 
    649 void
    650 fdstrategy(bp)
    651 	register struct buf *bp;	/* IO operation to perform */
    652 {
    653 	struct fd_softc *fd;
    654 	int unit = FDUNIT(bp->b_dev);
    655 	int sz;
    656  	int s;
    657 
    658 	if (unit >= fd_cd.cd_ndevs ||
    659 	    (fd = fd_cd.cd_devs[unit]) == 0 ||
    660 	    bp->b_blkno < 0 ||
    661 	    (bp->b_bcount % FDC_BSIZE) != 0) {
    662 		DPRINTF(("fdstrategy: unit=%d, blkno=%" PRId64 ", "
    663 			 "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 %" PRId64 " 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