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