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