Home | History | Annotate | Line # | Download | only in dev
hdfd.c revision 1.71.4.1
      1 /*	$NetBSD: hdfd.c,v 1.71.4.1 2010/05/30 05:16:39 rmind Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1996 Leo Weppelman
      5  * Copyright (c) 1990 The Regents of the University of California.
      6  * All rights reserved.
      7  *
      8  * This code is derived from software contributed to Berkeley by
      9  * Don Ahn.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  * 3. Neither the name of the University nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  *
     35  *	@(#)fd.c	7.4 (Berkeley) 5/25/91
     36  */
     37 
     38 /*-
     39  * Copyright (c) 1993, 1994, 1995, 1996
     40  *	Charles M. Hannum.  All rights reserved.
     41  *
     42  * This code is derived from software contributed to Berkeley by
     43  * Don Ahn.
     44  *
     45  * Redistribution and use in source and binary forms, with or without
     46  * modification, are permitted provided that the following conditions
     47  * are met:
     48  * 1. Redistributions of source code must retain the above copyright
     49  *    notice, this list of conditions and the following disclaimer.
     50  * 2. Redistributions in binary form must reproduce the above copyright
     51  *    notice, this list of conditions and the following disclaimer in the
     52  *    documentation and/or other materials provided with the distribution.
     53  * 3. All advertising materials mentioning features or use of this software
     54  *    must display the following acknowledgement:
     55  *	This product includes software developed by the University of
     56  *	California, Berkeley and its contributors.
     57  * 4. Neither the name of the University nor the names of its contributors
     58  *    may be used to endorse or promote products derived from this software
     59  *    without specific prior written permission.
     60  *
     61  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     62  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     63  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     64  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     65  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     66  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     67  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     68  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     69  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     70  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     71  * SUCH DAMAGE.
     72  *
     73  *	@(#)fd.c	7.4 (Berkeley) 5/25/91
     74  */
     75 
     76 /*
     77  * Floppy formatting facilities merged from FreeBSD fd.c driver:
     78  *	Id: fd.c,v 1.53 1995/03/12 22:40:56 joerg Exp
     79  * which carries the same copyright/redistribution notice as shown above with
     80  * the addition of the following statement before the "Redistribution and
     81  * use ..." clause:
     82  *
     83  * Copyright (c) 1993, 1994 by
     84  *  jc (at) irbs.UUCP (John Capo)
     85  *  vak (at) zebub.msk.su (Serge Vakulenko)
     86  *  ache (at) astral.msk.su (Andrew A. Chernov)
     87  *
     88  * Copyright (c) 1993, 1994, 1995 by
     89  *  joerg_wunsch (at) uriah.sax.de (Joerg Wunsch)
     90  *  dufault (at) hda.com (Peter Dufault)
     91  */
     92 
     93 #include <sys/cdefs.h>
     94 __KERNEL_RCSID(0, "$NetBSD: hdfd.c,v 1.71.4.1 2010/05/30 05:16:39 rmind Exp $");
     95 
     96 #include "opt_ddb.h"
     97 
     98 #include <sys/param.h>
     99 #include <sys/systm.h>
    100 #include <sys/callout.h>
    101 #include <sys/kernel.h>
    102 #include <sys/file.h>
    103 #include <sys/ioctl.h>
    104 #include <sys/device.h>
    105 #include <sys/disklabel.h>
    106 #include <sys/disk.h>
    107 #include <sys/buf.h>
    108 #include <sys/bufq.h>
    109 #include <sys/malloc.h>
    110 #include <sys/uio.h>
    111 #include <sys/syslog.h>
    112 #include <sys/queue.h>
    113 #include <sys/proc.h>
    114 #include <sys/fdio.h>
    115 #include <sys/conf.h>
    116 
    117 #include <uvm/uvm_extern.h>
    118 
    119 #include <machine/cpu.h>
    120 #include <machine/bus.h>
    121 #include <machine/iomap.h>
    122 #include <machine/mfp.h>
    123 #include <machine/intr.h>
    124 
    125 #include <atari/dev/hdfdreg.h>
    126 #include <atari/atari/device.h>
    127 
    128 #include "ioconf.h"
    129 #include "locators.h"
    130 
    131 /*
    132  * {b,c}devsw[] function prototypes
    133  */
    134 dev_type_open(fdopen);
    135 dev_type_close(fdclose);
    136 dev_type_read(fdread);
    137 dev_type_write(fdwrite);
    138 dev_type_ioctl(fdioctl);
    139 dev_type_strategy(fdstrategy);
    140 
    141 volatile u_char	*fdio_addr;
    142 
    143 #define wrt_fdc_reg(reg, val)	{ fdio_addr[reg] = val; }
    144 #define rd_fdc_reg(reg)		( fdio_addr[reg] )
    145 
    146 #define	fdc_ienable()		MFP2->mf_ierb |= IB_DCHG;
    147 
    148 /*
    149  * Interface to the pseudo-DMA handler
    150  */
    151 void	fddma_intr(void);
    152 void *	fddmaaddr  = NULL;
    153 int	fddmalen   = 0;
    154 
    155 extern void	mfp_hdfd_nf(void), mfp_hdfd_fifo(void);
    156 
    157 /*
    158  * Argument to fdcintr.....
    159  */
    160 static void	*intr_arg = NULL; /* XXX: arg. to intr_establish() */
    161 
    162 
    163 
    164 #define FDUNIT(dev)	(minor(dev) / 8)
    165 #define FDTYPE(dev)	(minor(dev) % 8)
    166 
    167 /* (mis)use device use flag to identify format operation */
    168 #define B_FORMAT B_DEVPRIVATE
    169 
    170 enum fdc_state {
    171 	DEVIDLE = 0,
    172 	MOTORWAIT,
    173 	DOSEEK,
    174 	SEEKWAIT,
    175 	SEEKTIMEDOUT,
    176 	SEEKCOMPLETE,
    177 	DOIO,
    178 	IOCOMPLETE,
    179 	IOTIMEDOUT,
    180 	DORESET,
    181 	RESETCOMPLETE,
    182 	RESETTIMEDOUT,
    183 	DORECAL,
    184 	RECALWAIT,
    185 	RECALTIMEDOUT,
    186 	RECALCOMPLETE,
    187 };
    188 
    189 /* software state, per controller */
    190 struct fdc_softc {
    191 	struct device	sc_dev;		/* boilerplate */
    192 
    193 	struct callout sc_timo_ch;	/* timeout callout */
    194 	struct callout sc_intr_ch;	/* pseudo-intr callout */
    195 
    196 	struct fd_softc	*sc_fd[4];	/* pointers to children */
    197 	TAILQ_HEAD(drivehead, fd_softc) sc_drives;
    198 	enum fdc_state	sc_state;
    199 	int		sc_errors;	/* number of retries so far */
    200 	int		sc_overruns;	/* number of overruns so far */
    201 	u_char		sc_status[7];	/* copy of registers */
    202 };
    203 
    204 /* controller driver configuration */
    205 int	fdcprobe(struct device *, struct cfdata *, void *);
    206 int	fdprint(void *, const char *);
    207 void	fdcattach(struct device *, struct device *, void *);
    208 
    209 CFATTACH_DECL(fdc, sizeof(struct fdc_softc),
    210     fdcprobe, fdcattach, NULL, NULL);
    211 
    212 /*
    213  * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
    214  * we tell them apart.
    215  */
    216 struct fd_type {
    217 	int	sectrac;	/* sectors per track */
    218 	int	heads;		/* number of heads */
    219 	int	seccyl;		/* sectors per cylinder */
    220 	int	secsize;	/* size code for sectors */
    221 	int	datalen;	/* data len when secsize = 0 */
    222 	int	steprate;	/* step rate and head unload time */
    223 	int	gap1;		/* gap len between sectors */
    224 	int	gap2;		/* formatting gap */
    225 	int	tracks;		/* total num of tracks */
    226 	int	size;		/* size of disk in sectors */
    227 	int	step;		/* steps per cylinder */
    228 	int	rate;		/* transfer speed code */
    229 	u_char	fillbyte;	/* format fill byte */
    230 	u_char	interleave;	/* interleave factor (formatting) */
    231 	const char *name;
    232 };
    233 
    234 /*
    235  * The order of entries in the following table is important -- BEWARE!
    236  * The order of the types is the same as for the TT/Falcon....
    237  */
    238 struct fd_type fd_types[] = {
    239         /* 360kB in 720kB drive */
    240         {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_125KBPS,0xf6,1,"360KB"  },
    241         /* 3.5" 720kB diskette */
    242         {  9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_125KBPS,0xf6,1,"720KB"  },
    243         /* 1.44MB diskette */
    244         { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_250KBPS,0xf6,1,"1.44MB" },
    245 };
    246 
    247 /* software state, per disk (with up to 4 disks per ctlr) */
    248 struct fd_softc {
    249 	struct device	sc_dev;
    250 	struct disk	sc_dk;
    251 
    252 	struct fd_type	*sc_deftype;	/* default type descriptor */
    253 	struct fd_type	*sc_type;	/* current type descriptor */
    254 
    255 	struct callout	sc_motoron_ch;
    256 	struct callout	sc_motoroff_ch;
    257 
    258 	daddr_t		sc_blkno;	/* starting block number */
    259 	int		sc_bcount;	/* byte count left */
    260  	int		sc_opts;	/* user-set options */
    261 	int		sc_skip;	/* bytes already transferred */
    262 	int		sc_nblks;	/* #blocks currently transferring */
    263 	int		sc_nbytes;	/* #bytes currently transferring */
    264 
    265 	int		sc_drive;	/* physical unit number */
    266 	int		sc_flags;
    267 #define	FD_OPEN		0x01		/* it's open */
    268 #define	FD_MOTOR	0x02		/* motor should be on */
    269 #define	FD_MOTOR_WAIT	0x04		/* motor coming up */
    270 #define	FD_HAVELAB	0x08		/* got a disklabel */
    271 	int		sc_cylin;	/* where we think the head is */
    272 
    273 	void		*sc_sdhook;	/* saved shutdown hook for drive. */
    274 
    275 	TAILQ_ENTRY(fd_softc) sc_drivechain;
    276 	int		sc_ops;		/* I/O ops since last switch */
    277 	struct bufq_state *sc_q;	/* pending I/O requests */
    278 	int		sc_active;	/* number of active I/O operations */
    279 };
    280 
    281 /* floppy driver configuration */
    282 int	fdprobe(struct device *, struct cfdata *, void *);
    283 void	fdattach(struct device *, struct device *, void *);
    284 
    285 CFATTACH_DECL(hdfd, sizeof(struct fd_softc),
    286     fdprobe, fdattach, NULL, NULL);
    287 
    288 const struct bdevsw fd_bdevsw = {
    289 	fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK
    290 };
    291 
    292 const struct cdevsw fd_cdevsw = {
    293 	fdopen, fdclose, fdread, fdwrite, fdioctl,
    294 	nostop, notty, nopoll, nommap, nokqfilter, D_DISK
    295 };
    296 
    297 void	fdstart(struct fd_softc *);
    298 
    299 struct dkdriver fddkdriver = { fdstrategy };
    300 
    301 void	fd_set_motor(struct fdc_softc *fdc, int reset);
    302 void	fd_motor_off(void *arg);
    303 void	fd_motor_on(void *arg);
    304 int	fdcresult(struct fdc_softc *fdc);
    305 int	out_fdc(u_char x);
    306 void	fdc_ctrl_intr(struct clockframe);
    307 void	fdcstart(struct fdc_softc *fdc);
    308 void	fdcstatus(struct device *dv, int n, const char *s);
    309 void	fdctimeout(void *arg);
    310 void	fdcpseudointr(void *arg);
    311 int	fdcintr(void *);
    312 void	fdcretry(struct fdc_softc *fdc);
    313 void	fdfinish(struct fd_softc *fd, struct buf *bp);
    314 int	fdformat(dev_t, struct ne7_fd_formb *, struct proc *);
    315 
    316 static void	fdgetdisklabel(struct fd_softc *, dev_t);
    317 static void	fdgetdefaultlabel(struct fd_softc *, struct disklabel *,
    318 		    int);
    319 
    320 inline struct fd_type *fd_dev_to_type(struct fd_softc *, dev_t);
    321 
    322 int
    323 fdcprobe(struct device *parent, struct cfdata *cfp, void *aux)
    324 {
    325 	static int	fdc_matched = 0;
    326 	bus_space_tag_t mb_tag;
    327 	bus_space_handle_t handle;
    328 
    329 	/* Match only once */
    330 	if (strcmp("fdc", aux) || fdc_matched)
    331 		return 0;
    332 
    333 	if (!atari_realconfig)
    334 		return 0;
    335 
    336 	if ((mb_tag = mb_alloc_bus_space_tag()) == NULL)
    337 		return 0;
    338 
    339 	if (bus_space_map(mb_tag, FD_IOBASE, FD_IOSIZE, 0, &handle)) {
    340 		printf("fdcprobe: cannot map io-area\n");
    341 		mb_free_bus_space_tag(mb_tag);
    342 		return 0;
    343 	}
    344 	fdio_addr = bus_space_vaddr(mb_tag, handle);	/* XXX */
    345 
    346 #ifdef FD_DEBUG
    347 	printf("fdcprobe: I/O mapping done va: %p\n", fdio_addr);
    348 #endif
    349 
    350 	/* reset */
    351 	wrt_fdc_reg(fdout, 0);
    352 	delay(100);
    353 	wrt_fdc_reg(fdout, FDO_FRST);
    354 
    355 	/* see if it can handle a command */
    356 	if (out_fdc(NE7CMD_SPECIFY) < 0)
    357 		goto out;
    358 	out_fdc(0xdf);
    359 	out_fdc(7);
    360 
    361 	fdc_matched = 1;
    362 
    363  out:
    364 	if (fdc_matched == 0) {
    365 		bus_space_unmap(mb_tag, handle, FD_IOSIZE);
    366 		mb_free_bus_space_tag(mb_tag);
    367 	}
    368 
    369 	return fdc_matched;
    370 }
    371 
    372 /*
    373  * Arguments passed between fdcattach and fdprobe.
    374  */
    375 struct fdc_attach_args {
    376 	int fa_drive;
    377 	struct fd_type *fa_deftype;
    378 };
    379 
    380 /*
    381  * Print the location of a disk drive (called just before attaching the
    382  * the drive).  If `fdc' is not NULL, the drive was found but was not
    383  * in the system config file; print the drive name as well.
    384  * Return QUIET (config_find ignores this if the device was configured) to
    385  * avoid printing `fdN not configured' messages.
    386  */
    387 int
    388 fdprint(void *aux, const char *fdc)
    389 {
    390 	register struct fdc_attach_args *fa = aux;
    391 
    392 	if (!fdc)
    393 		aprint_normal(" drive %d", fa->fa_drive);
    394 	return QUIET;
    395 }
    396 
    397 void
    398 fdcattach(struct device *parent, struct device *self, void *aux)
    399 {
    400 	struct fdc_softc	*fdc = (void *)self;
    401 	struct fdc_attach_args	fa;
    402 	int			has_fifo;
    403 
    404 	has_fifo = 0;
    405 
    406 	fdc->sc_state = DEVIDLE;
    407 	TAILQ_INIT(&fdc->sc_drives);
    408 
    409 	out_fdc(NE7CMD_CONFIGURE);
    410 	if (out_fdc(0) == 0) {
    411 		out_fdc(0x1a);	/* No polling, fifo depth = 10	*/
    412 		out_fdc(0);
    413 
    414 		/* Retain configuration across resets	*/
    415 		out_fdc(NE7CMD_LOCK);
    416 		(void)fdcresult(fdc);
    417 		has_fifo = 1;
    418 	} else {
    419 		(void)rd_fdc_reg(fddata);
    420 		printf(": no fifo");
    421 	}
    422 
    423 	printf("\n");
    424 
    425 	callout_init(&fdc->sc_timo_ch, 0);
    426 	callout_init(&fdc->sc_intr_ch, 0);
    427 
    428 	if (intr_establish(22, USER_VEC|FAST_VEC, 0,
    429 			   (hw_ifun_t)(has_fifo ? mfp_hdfd_fifo : mfp_hdfd_nf),
    430 			   NULL) == NULL) {
    431 		printf("fdcattach: Can't establish interrupt\n");
    432 		return;
    433 	}
    434 
    435 	/*
    436 	 * Setup the interrupt logic.
    437 	 */
    438 	MFP2->mf_iprb  = (u_int8_t)~IB_DCHG;
    439 	MFP2->mf_imrb |= IB_DCHG;
    440 	MFP2->mf_aer  |= 0x10; /* fdc int low->high */
    441 
    442 	/* physical limit: four drives per controller. */
    443 	for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
    444 		/*
    445 		 * XXX: Choose something sensible as a default...
    446 		 */
    447 		fa.fa_deftype = &fd_types[2]; /* 1.44MB */
    448 		(void)config_found(self, (void *)&fa, fdprint);
    449 	}
    450 }
    451 
    452 int
    453 fdprobe(struct device *parent, struct cfdata *cfp, void *aux)
    454 {
    455 	struct fdc_softc	*fdc = (void *)parent;
    456 	struct fdc_attach_args	*fa = aux;
    457 	int			drive = fa->fa_drive;
    458 	int			n;
    459 
    460 	if (cfp->cf_loc[FDCCF_UNIT] != FDCCF_UNIT_DEFAULT &&
    461 	    cfp->cf_loc[FDCCF_UNIT] != drive)
    462 		return 0;
    463 	/*
    464 	 * XXX
    465 	 * This is to work around some odd interactions between this driver
    466 	 * and SMC Ethernet cards.
    467 	 */
    468 	if (cfp->cf_loc[FDCCF_UNIT] == FDCCF_UNIT_DEFAULT && drive >= 2)
    469 		return 0;
    470 
    471 	/* select drive and turn on motor */
    472 	wrt_fdc_reg(fdout, drive | FDO_FRST | FDO_MOEN(drive));
    473 
    474 	/* wait for motor to spin up */
    475 	delay(250000);
    476 	out_fdc(NE7CMD_RECAL);
    477 	out_fdc(drive);
    478 
    479 	/* wait for recalibrate */
    480 	delay(2000000);
    481 	out_fdc(NE7CMD_SENSEI);
    482 	n = fdcresult(fdc);
    483 
    484 #ifdef FD_DEBUG
    485 	{
    486 		int i;
    487 		printf("fdprobe: status");
    488 		for (i = 0; i < n; i++)
    489 			printf(" %x", fdc->sc_status[i]);
    490 		printf("\n");
    491 	}
    492 #endif
    493 	intr_arg = (void*)fdc;
    494 	if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20)
    495 		return 0;
    496 	/* turn off motor */
    497 	wrt_fdc_reg(fdout, FDO_FRST);
    498 
    499 	return 1;
    500 }
    501 
    502 /*
    503  * Controller is working, and drive responded.  Attach it.
    504  */
    505 void
    506 fdattach(struct device *parent, struct device *self, void *aux)
    507 {
    508 	struct fdc_softc	*fdc  = (void *)parent;
    509 	struct fd_softc		*fd   = (void *)self;
    510 	struct fdc_attach_args	*fa   = aux;
    511 	struct fd_type		*type = fa->fa_deftype;
    512 	int			drive = fa->fa_drive;
    513 
    514 	callout_init(&fd->sc_motoron_ch, 0);
    515 	callout_init(&fd->sc_motoroff_ch, 0);
    516 
    517 	/* XXX Allow `flags' to override device type? */
    518 
    519 	if (type)
    520 		printf(": %s %d cyl, %d head, %d sec\n", type->name,
    521 		    type->tracks, type->heads, type->sectrac);
    522 	else
    523 		printf(": density unknown\n");
    524 
    525 	bufq_alloc(&fd->sc_q, "disksort", BUFQ_SORT_CYLINDER);
    526 	fd->sc_cylin      = -1;
    527 	fd->sc_drive      = drive;
    528 	fd->sc_deftype    = type;
    529 	fdc->sc_fd[drive] = fd;
    530 
    531 	/*
    532 	 * Initialize and attach the disk structure.
    533 	 */
    534 	disk_init(&fd->sc_dk, fd->sc_dev.dv_xname, &fddkdriver);
    535 	disk_attach(&fd->sc_dk);
    536 
    537 	/* Needed to power off if the motor is on when we halt. */
    538 	fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd);
    539 }
    540 
    541 /*
    542  * This is called from the assembly part of the interrupt handler
    543  * when it is clear that the interrupt was not related to shoving
    544  * data.
    545  */
    546 void
    547 fdc_ctrl_intr(struct clockframe frame)
    548 {
    549 	int	s;
    550 
    551 	/*
    552 	 * Disable further interrupts. The fdcintr() routine
    553 	 * explicitly enables them when needed.
    554 	 */
    555 	MFP2->mf_ierb &= ~IB_DCHG;
    556 
    557 	/*
    558 	 * Set fddmalen to zero so no pseudo-DMA transfers will
    559 	 * occur.
    560 	 */
    561 	fddmalen = 0;
    562 
    563 	if (!BASEPRI(frame.cf_sr)) {
    564 		/*
    565 		 * We don't want to stay on ipl6.....
    566 		 */
    567 		add_sicallback((si_farg)fdcpseudointr, intr_arg, 0);
    568 	} else {
    569 		s = splbio();
    570 		(void) fdcintr(intr_arg);
    571 		splx(s);
    572 	}
    573 }
    574 
    575 inline struct fd_type *
    576 fd_dev_to_type(struct fd_softc *fd, dev_t dev)
    577 {
    578 	int type = FDTYPE(dev);
    579 
    580 	if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
    581 		return NULL;
    582 	return type ? &fd_types[type - 1] : fd->sc_deftype;
    583 }
    584 
    585 void
    586 fdstrategy(struct buf *bp)
    587 {
    588 	struct fd_softc *fd = device_lookup_private(&hdfd_cd, FDUNIT(bp->b_dev));
    589 	int sz;
    590  	int s;
    591 
    592 	/* Valid unit, controller, and request? */
    593 	if (bp->b_blkno < 0 ||
    594 	    ((bp->b_bcount % FDC_BSIZE) != 0 &&
    595 	     (bp->b_flags & B_FORMAT) == 0)) {
    596 		bp->b_error = EINVAL;
    597 		goto done;
    598 	}
    599 
    600 	/* If it's a null transfer, return immediately. */
    601 	if (bp->b_bcount == 0)
    602 		goto done;
    603 
    604 	sz = howmany(bp->b_bcount, FDC_BSIZE);
    605 
    606 	if (bp->b_blkno + sz > fd->sc_type->size) {
    607 		sz = fd->sc_type->size - bp->b_blkno;
    608 		if (sz == 0) {
    609 			/* If exactly at end of disk, return EOF. */
    610 			goto done;
    611 		}
    612 		if (sz < 0) {
    613 			/* If past end of disk, return EINVAL. */
    614 			bp->b_error = EINVAL;
    615 			goto done;
    616 		}
    617 		/* Otherwise, truncate request. */
    618 		bp->b_bcount = sz << DEV_BSHIFT;
    619 	}
    620 
    621 	bp->b_rawblkno = bp->b_blkno;
    622  	bp->b_cylinder = bp->b_blkno / (FDC_BSIZE/DEV_BSIZE) / fd->sc_type->seccyl;
    623 
    624 #ifdef FD_DEBUG
    625 	printf("fdstrategy: b_blkno %d b_bcount %ld blkno %qd cylin %ld sz"
    626 		" %d\n", bp->b_blkno, bp->b_bcount, (long)fd->sc_blkno,
    627 		bp->b_cylinder, sz);
    628 #endif
    629 
    630 	/* Queue transfer on drive, activate drive and controller if idle. */
    631 	s = splbio();
    632 	bufq_put(fd->sc_q, bp);
    633 	callout_stop(&fd->sc_motoroff_ch);		/* a good idea */
    634 	if (fd->sc_active == 0)
    635 		fdstart(fd);
    636 #ifdef DIAGNOSTIC
    637 	else {
    638 		struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
    639 		if (fdc->sc_state == DEVIDLE) {
    640 			printf("fdstrategy: controller inactive\n");
    641 			fdcstart(fdc);
    642 		}
    643 	}
    644 #endif
    645 	splx(s);
    646 	return;
    647 
    648 done:
    649 	/* Toss transfer; we're done early. */
    650 	bp->b_resid = bp->b_bcount;
    651 	biodone(bp);
    652 }
    653 
    654 void
    655 fdstart(struct fd_softc *fd)
    656 {
    657 	struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
    658 	int active = fdc->sc_drives.tqh_first != 0;
    659 
    660 	/* Link into controller queue. */
    661 	fd->sc_active = 1;
    662 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    663 
    664 	/* If controller not already active, start it. */
    665 	if (!active)
    666 		fdcstart(fdc);
    667 }
    668 
    669 void
    670 fdfinish(struct fd_softc *fd, struct buf *bp)
    671 {
    672 	struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
    673 
    674 	/*
    675 	 * Move this drive to the end of the queue to give others a `fair'
    676 	 * chance.  We only force a switch if N operations are completed while
    677 	 * another drive is waiting to be serviced, since there is a long motor
    678 	 * startup delay whenever we switch.
    679 	 */
    680 	(void)bufq_get(fd->sc_q);
    681 	if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
    682 		fd->sc_ops = 0;
    683 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
    684 		if (bufq_peek(fd->sc_q) != NULL)
    685 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
    686 		else
    687 			fd->sc_active = 0;
    688 	}
    689 	bp->b_resid = fd->sc_bcount;
    690 	fd->sc_skip = 0;
    691 
    692 	biodone(bp);
    693 	/* turn off motor 5s from now */
    694 	callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
    695 	fdc->sc_state = DEVIDLE;
    696 }
    697 
    698 int
    699 fdread(dev_t dev, struct uio *uio, int flags)
    700 {
    701 
    702 	return physio(fdstrategy, NULL, dev, B_READ, minphys, uio);
    703 }
    704 
    705 int
    706 fdwrite(dev_t dev, struct uio *uio, int flags)
    707 {
    708 
    709 	return physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio);
    710 }
    711 
    712 void
    713 fd_set_motor(struct fdc_softc *fdc, int reset)
    714 {
    715 	struct fd_softc *fd;
    716 	u_char status;
    717 	int n;
    718 
    719 	if ((fd = fdc->sc_drives.tqh_first) != NULL)
    720 		status = fd->sc_drive;
    721 	else
    722 		status = 0;
    723 	if (!reset)
    724 		status |= FDO_FRST | FDO_FDMAEN;
    725 	for (n = 0; n < 4; n++)
    726 		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
    727 			status |= FDO_MOEN(n);
    728 	wrt_fdc_reg(fdout, status);
    729 }
    730 
    731 void
    732 fd_motor_off(void *arg)
    733 {
    734 	struct fd_softc *fd = arg;
    735 	int s;
    736 
    737 	s = splbio();
    738 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
    739 	fd_set_motor((struct fdc_softc *) device_parent(&fd->sc_dev), 0);
    740 	splx(s);
    741 }
    742 
    743 void
    744 fd_motor_on(void *arg)
    745 {
    746 	struct fd_softc *fd = arg;
    747 	struct fdc_softc *fdc = (void *) device_parent(&fd->sc_dev);
    748 	int s;
    749 
    750 	s = splbio();
    751 	fd->sc_flags &= ~FD_MOTOR_WAIT;
    752 	if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
    753 		(void) fdcintr(fdc);
    754 	splx(s);
    755 }
    756 
    757 int
    758 fdcresult(struct fdc_softc *fdc)
    759 {
    760 	u_char i;
    761 	int j = 100000,
    762 	    n = 0;
    763 
    764 	for (; j; j--) {
    765 		i = rd_fdc_reg(fdsts) & (NE7_DIO | NE7_RQM | NE7_CB);
    766 		if (i == NE7_RQM)
    767 			return n;
    768 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
    769 			if (n >= sizeof(fdc->sc_status)) {
    770 				log(LOG_ERR, "fdcresult: overrun\n");
    771 				return -1;
    772 			}
    773 			fdc->sc_status[n++] = rd_fdc_reg(fddata);
    774 		}
    775 		else
    776 			delay(10);
    777 	}
    778 	log(LOG_ERR, "fdcresult: timeout\n");
    779 	return -1;
    780 }
    781 
    782 int
    783 out_fdc(u_char x)
    784 {
    785 	int i = 100000;
    786 
    787 	while (((rd_fdc_reg(fdsts) & (NE7_DIO|NE7_RQM)) != NE7_RQM) && i-- > 0)
    788 		delay(1);
    789 	if (i <= 0)
    790 		return -1;
    791 	wrt_fdc_reg(fddata, x);
    792 	return 0;
    793 }
    794 
    795 int
    796 fdopen(dev_t dev, int flags, int mode, struct lwp *l)
    797 {
    798 	struct fd_softc *fd;
    799 	struct fd_type *type;
    800 
    801 	fd = device_lookup_private(&hdfd_cd, FDUNIT(dev));
    802 	if (fd == NULL)
    803 		return ENXIO;
    804 	type = fd_dev_to_type(fd, dev);
    805 	if (type == NULL)
    806 		return ENXIO;
    807 
    808 	if ((fd->sc_flags & FD_OPEN) != 0 &&
    809 	    fd->sc_type != type)
    810 		return EBUSY;
    811 
    812 	fd->sc_type = type;
    813 	fd->sc_cylin = -1;
    814 	fd->sc_flags |= FD_OPEN;
    815 	fdgetdisklabel(fd, dev);
    816 
    817 	return 0;
    818 }
    819 
    820 int
    821 fdclose(dev_t dev, int flags, int mode, struct lwp *l)
    822 {
    823 	struct fd_softc *fd = device_lookup_private(&hdfd_cd, FDUNIT(dev));
    824 
    825 	fd->sc_flags &= ~(FD_OPEN|FD_HAVELAB);
    826 	fd->sc_opts  &= ~(FDOPT_NORETRY|FDOPT_SILENT);
    827 	return 0;
    828 }
    829 
    830 void
    831 fdcstart(struct fdc_softc *fdc)
    832 {
    833 
    834 #ifdef DIAGNOSTIC
    835 	/* only got here if controller's drive queue was inactive; should
    836 	   be in idle state */
    837 	if (fdc->sc_state != DEVIDLE) {
    838 		printf("fdcstart: not idle\n");
    839 		return;
    840 	}
    841 #endif
    842 	(void) fdcintr(fdc);
    843 }
    844 
    845 static void
    846 fdcpstatus(struct fdc_softc *fdc)
    847 {
    848 	char bits[64];
    849 
    850 	snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]);
    851 	printf(" (st0 %s", bits);
    852 	snprintb(bits, sizeof(bits), NE7_ST1BITS, fdc->sc_status[1]);
    853 	printf(" st1 %s", bits);
    854 	snprintb(bits, sizeof(bits), NE7_ST2BITS, fdc->sc_status[2]);
    855 	printf(" st2 %s", bits);
    856 	printf(" cyl %d head %d sec %d)\n",
    857 	    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
    858 }
    859 
    860 void
    861 fdcstatus(struct device *dv, int n, const char *s)
    862 {
    863 	struct fdc_softc *fdc = (void *) device_parent(dv);
    864 	char bits[64];
    865 
    866 	if (n == 0) {
    867 		out_fdc(NE7CMD_SENSEI);
    868 		(void) fdcresult(fdc);
    869 		n = 2;
    870 	}
    871 
    872 	printf("%s: %s", dv->dv_xname, s);
    873 
    874 	switch (n) {
    875 	case 0:
    876 		printf("\n");
    877 		break;
    878 	case 2:
    879 		snprintb(bits, sizeof(bits), NE7_ST0BITS, fdc->sc_status[0]);
    880 		printf(" (st0 %s cyl %d)\n", bits, fdc->sc_status[1]);
    881 		break;
    882 	case 7:
    883 		fdcpstatus(fdc);
    884 		break;
    885 #ifdef DIAGNOSTIC
    886 	default:
    887 		printf("\nfdcstatus: weird size");
    888 		break;
    889 #endif
    890 	}
    891 }
    892 
    893 void
    894 fdctimeout(void *arg)
    895 {
    896 	struct fdc_softc *fdc = arg;
    897 	struct fd_softc *fd = fdc->sc_drives.tqh_first;
    898 	int s;
    899 
    900 	s = splbio();
    901 	fdcstatus(&fd->sc_dev, 0, "timeout");
    902 
    903 	if (bufq_peek(fd->sc_q) != NULL)
    904 		fdc->sc_state++;
    905 	else
    906 		fdc->sc_state = DEVIDLE;
    907 
    908 	(void) fdcintr(fdc);
    909 	splx(s);
    910 }
    911 
    912 void
    913 fdcpseudointr(void *arg)
    914 {
    915 	int s;
    916 
    917 	/* Just ensure it has the right spl. */
    918 	s = splbio();
    919 	(void) fdcintr(arg);
    920 	splx(s);
    921 }
    922 
    923 int
    924 fdcintr(void *arg)
    925 {
    926 	struct fdc_softc	*fdc = arg;
    927 #define	st0	fdc->sc_status[0]
    928 #define	st1	fdc->sc_status[1]
    929 #define	cyl	fdc->sc_status[1]
    930 
    931 	struct fd_softc		*fd;
    932 	struct buf		*bp;
    933 	int			read, head, sec, i, nblks;
    934 	struct fd_type		*type;
    935 	struct ne7_fd_formb	*finfo = NULL;
    936 
    937 loop:
    938 	/* Is there a drive for the controller to do a transfer with? */
    939 	fd = fdc->sc_drives.tqh_first;
    940 	if (fd == NULL) {
    941 		fdc->sc_state = DEVIDLE;
    942  		return 1;
    943 	}
    944 
    945 	/* Is there a transfer to this drive?  If not, deactivate drive. */
    946 	bp = bufq_peek(fd->sc_q);
    947 	if (bp == NULL) {
    948 		fd->sc_ops = 0;
    949 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
    950 		fd->sc_active = 0;
    951 		goto loop;
    952 	}
    953 
    954 	if (bp->b_flags & B_FORMAT)
    955 		finfo = (struct ne7_fd_formb *)bp->b_data;
    956 
    957 	switch (fdc->sc_state) {
    958 	case DEVIDLE:
    959 		fdc->sc_errors = 0;
    960 		fdc->sc_overruns = 0;
    961 		fd->sc_skip = 0;
    962 		fd->sc_bcount = bp->b_bcount;
    963 		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
    964 		callout_stop(&fd->sc_motoroff_ch);
    965 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
    966 			fdc->sc_state = MOTORWAIT;
    967 			return 1;
    968 		}
    969 		if ((fd->sc_flags & FD_MOTOR) == 0) {
    970 			/* Turn on the motor, being careful about pairing. */
    971 			struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
    972 			if (ofd && ofd->sc_flags & FD_MOTOR) {
    973 				callout_stop(&ofd->sc_motoroff_ch);
    974 				ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
    975 			}
    976 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
    977 			fd_set_motor(fdc, 0);
    978 			fdc->sc_state = MOTORWAIT;
    979 			/* Allow .25s for motor to stabilize. */
    980 			callout_reset(&fd->sc_motoron_ch, hz / 4,
    981 			    fd_motor_on, fd);
    982 			return 1;
    983 		}
    984 		/* Make sure the right drive is selected. */
    985 		fd_set_motor(fdc, 0);
    986 
    987 		/* fall through */
    988 	case DOSEEK:
    989 	doseek:
    990 		if (fd->sc_cylin == bp->b_cylinder)
    991 			goto doio;
    992 
    993 		out_fdc(NE7CMD_SPECIFY);/* specify command */
    994 		out_fdc(fd->sc_type->steprate);
    995 		out_fdc(0x7);	/* XXX head load time == 6ms - non-DMA */
    996 
    997 		fdc_ienable();
    998 
    999 		out_fdc(NE7CMD_SEEK);	/* seek function */
   1000 		out_fdc(fd->sc_drive);	/* drive number */
   1001 		out_fdc(bp->b_cylinder * fd->sc_type->step);
   1002 
   1003 		fd->sc_cylin = -1;
   1004 		fdc->sc_state = SEEKWAIT;
   1005 
   1006 		iostat_seek(fd->sc_dk.dk_stats);
   1007 		disk_busy(&fd->sc_dk);
   1008 
   1009 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
   1010 		return 1;
   1011 
   1012 	case DOIO:
   1013 	doio:
   1014 		if (finfo)
   1015 			fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
   1016 				      (char *)finfo;
   1017 
   1018 		type  = fd->sc_type;
   1019 		sec   = fd->sc_blkno % type->seccyl;
   1020 		head  = sec / type->sectrac;
   1021 		sec  -= head * type->sectrac;
   1022 		nblks = type->sectrac - sec;
   1023 		nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
   1024 		nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
   1025 		fd->sc_nblks  = nblks;
   1026 		fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
   1027 #ifdef DIAGNOSTIC
   1028 		{
   1029 		     int block;
   1030 
   1031 		     block = (fd->sc_cylin * type->heads + head)
   1032 				* type->sectrac + sec;
   1033 		     if (block != fd->sc_blkno) {
   1034 			 printf("fdcintr: block %d != blkno %qd\n",
   1035 						block, fd->sc_blkno);
   1036 #ifdef DDB
   1037 			 Debugger();
   1038 #endif
   1039 		     }
   1040 		}
   1041 #endif
   1042 		read = bp->b_flags & B_READ ? 1 : 0;
   1043 
   1044 		/*
   1045 		 * Setup pseudo-DMA address & count
   1046 		 */
   1047 		fddmaaddr = (char *)bp->b_data + fd->sc_skip;
   1048 		fddmalen  = fd->sc_nbytes;
   1049 
   1050 		wrt_fdc_reg(fdctl, type->rate);
   1051 #ifdef FD_DEBUG
   1052 		printf("fdcintr: %s drive %d track %d head %d sec %d"
   1053 			" nblks %d\n", read ? "read" : "write",
   1054 			fd->sc_drive, fd->sc_cylin, head, sec, nblks);
   1055 #endif
   1056 		fdc_ienable();
   1057 
   1058 		if (finfo) {
   1059 			/* formatting */
   1060 			if (out_fdc(NE7CMD_FORMAT) < 0) {
   1061 				fdc->sc_errors = 4;
   1062 				fdcretry(fdc);
   1063 				goto loop;
   1064 			}
   1065 			out_fdc((head << 2) | fd->sc_drive);
   1066 			out_fdc(finfo->fd_formb_secshift);
   1067 			out_fdc(finfo->fd_formb_nsecs);
   1068 			out_fdc(finfo->fd_formb_gaplen);
   1069 			out_fdc(finfo->fd_formb_fillbyte);
   1070 		} else {
   1071 			if (read)
   1072 				out_fdc(NE7CMD_READ);	/* READ */
   1073 			else
   1074 				out_fdc(NE7CMD_WRITE);	/* WRITE */
   1075 			out_fdc((head << 2) | fd->sc_drive);
   1076 			out_fdc(fd->sc_cylin);		/* track	 */
   1077 			out_fdc(head);			/* head		 */
   1078 			out_fdc(sec + 1);		/* sector +1	 */
   1079 			out_fdc(type->secsize);		/* sector size   */
   1080 			out_fdc(sec + nblks);		/* last sectors	 */
   1081 			out_fdc(type->gap1);		/* gap1 size	 */
   1082 			out_fdc(type->datalen);		/* data length	 */
   1083 		}
   1084 		fdc->sc_state = IOCOMPLETE;
   1085 
   1086 		disk_busy(&fd->sc_dk);
   1087 
   1088 		/* allow 2 seconds for operation */
   1089 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
   1090 		return 1;				/* will return later */
   1091 
   1092 	case SEEKWAIT:
   1093 		callout_stop(&fdc->sc_timo_ch);
   1094 		fdc->sc_state = SEEKCOMPLETE;
   1095 		/* allow 1/50 second for heads to settle */
   1096 		callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
   1097 		return 1;
   1098 
   1099 	case SEEKCOMPLETE:
   1100 		/* no data on seek */
   1101 		disk_unbusy(&fd->sc_dk, 0, 0);
   1102 
   1103 		/* Make sure seek really happened. */
   1104 		out_fdc(NE7CMD_SENSEI);
   1105 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
   1106 		    cyl != bp->b_cylinder * fd->sc_type->step) {
   1107 #ifdef FD_DEBUG
   1108 			fdcstatus(&fd->sc_dev, 2, "seek failed");
   1109 #endif
   1110 			fdcretry(fdc);
   1111 			goto loop;
   1112 		}
   1113 		fd->sc_cylin = bp->b_cylinder;
   1114 		goto doio;
   1115 
   1116 	case IOTIMEDOUT:
   1117 	case SEEKTIMEDOUT:
   1118 	case RECALTIMEDOUT:
   1119 	case RESETTIMEDOUT:
   1120 		fdcretry(fdc);
   1121 		goto loop;
   1122 
   1123 	case IOCOMPLETE: /* IO DONE, post-analyze */
   1124 		callout_stop(&fdc->sc_timo_ch);
   1125 
   1126 		disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
   1127 		    (bp->b_flags & B_READ));
   1128 
   1129 		if (fdcresult(fdc) != 7 || (st1 & 0x37) != 0) {
   1130 			/*
   1131 			 * As the damn chip doesn't seem to have a FIFO,
   1132 			 * accept a few overruns as a fact of life *sigh*
   1133 			 */
   1134 			if ((st1 & 0x10) && (++fdc->sc_overruns < 4)) {
   1135 				fdc->sc_state = DOSEEK;
   1136 				goto loop;
   1137 			}
   1138 #ifdef FD_DEBUG
   1139 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
   1140 			    "read failed" : "write failed");
   1141 			printf("blkno %qd nblks %d\n",
   1142 			    fd->sc_blkno, fd->sc_nblks);
   1143 #endif
   1144 			fdcretry(fdc);
   1145 			goto loop;
   1146 		}
   1147 		if (fdc->sc_errors) {
   1148 			diskerr(bp, "fd", "soft error", LOG_PRINTF,
   1149 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
   1150 			printf("\n");
   1151 			fdc->sc_errors = 0;
   1152 		}
   1153 		fdc->sc_overruns = 0;
   1154 		fd->sc_blkno += fd->sc_nblks;
   1155 		fd->sc_skip += fd->sc_nbytes;
   1156 		fd->sc_bcount -= fd->sc_nbytes;
   1157 		if (!finfo && fd->sc_bcount > 0) {
   1158 			bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
   1159 			goto doseek;
   1160 		}
   1161 		fdfinish(fd, bp);
   1162 		goto loop;
   1163 
   1164 	case DORESET:
   1165 		/* try a reset, keep motor on */
   1166 		fd_set_motor(fdc, 1);
   1167 		delay(100);
   1168 		fd_set_motor(fdc, 0);
   1169 		fdc->sc_state = RESETCOMPLETE;
   1170 		callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
   1171 		return 1;			/* will return later */
   1172 
   1173 	case RESETCOMPLETE:
   1174 		callout_stop(&fdc->sc_timo_ch);
   1175 		/* clear the controller output buffer */
   1176 		for (i = 0; i < 4; i++) {
   1177 			out_fdc(NE7CMD_SENSEI);
   1178 			(void) fdcresult(fdc);
   1179 		}
   1180 
   1181 		/* fall through */
   1182 	case DORECAL:
   1183 		fdc_ienable();
   1184 
   1185 		out_fdc(NE7CMD_RECAL);	/* recalibrate function */
   1186 		out_fdc(fd->sc_drive);
   1187 		fdc->sc_state = RECALWAIT;
   1188 		callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
   1189 		return 1;			/* will return later */
   1190 
   1191 	case RECALWAIT:
   1192 		callout_stop(&fdc->sc_timo_ch);
   1193 		fdc->sc_state = RECALCOMPLETE;
   1194 		/* allow 1/30 second for heads to settle */
   1195 		callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
   1196 		return 1;			/* will return later */
   1197 
   1198 	case RECALCOMPLETE:
   1199 		out_fdc(NE7CMD_SENSEI);
   1200 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
   1201 #ifdef FD_DEBUG
   1202 			fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
   1203 #endif
   1204 			fdcretry(fdc);
   1205 			goto loop;
   1206 		}
   1207 		fd->sc_cylin = 0;
   1208 		goto doseek;
   1209 
   1210 	case MOTORWAIT:
   1211 		if (fd->sc_flags & FD_MOTOR_WAIT)
   1212 			return 1;		/* time's not up yet */
   1213 		goto doseek;
   1214 
   1215 	default:
   1216 		fdcstatus(&fd->sc_dev, 0, "stray interrupt");
   1217 		return 1;
   1218 	}
   1219 #ifdef DIAGNOSTIC
   1220 	panic("fdcintr: impossible");
   1221 #endif
   1222 #undef	st0
   1223 #undef	st1
   1224 #undef	cyl
   1225 }
   1226 
   1227 void
   1228 fdcretry(struct fdc_softc *fdc)
   1229 {
   1230 	struct fd_softc *fd;
   1231 	struct buf *bp;
   1232 
   1233 	fd = fdc->sc_drives.tqh_first;
   1234 	bp = bufq_peek(fd->sc_q);
   1235 
   1236 	if (fd->sc_opts & FDOPT_NORETRY)
   1237 	    goto fail;
   1238 
   1239 	switch (fdc->sc_errors) {
   1240 	case 0:
   1241 		/* try again */
   1242 		fdc->sc_state = DOSEEK;
   1243 		break;
   1244 
   1245 	case 1: case 2: case 3:
   1246 		/* didn't work; try recalibrating */
   1247 		fdc->sc_state = DORECAL;
   1248 		break;
   1249 
   1250 	case 4:
   1251 		/* still no go; reset the bastard */
   1252 		fdc->sc_state = DORESET;
   1253 		break;
   1254 
   1255 	default:
   1256 	fail:
   1257 		if ((fd->sc_opts & FDOPT_SILENT) == 0) {
   1258 			diskerr(bp, "fd", "hard error", LOG_PRINTF,
   1259 				fd->sc_skip / FDC_BSIZE,
   1260 				(struct disklabel *)NULL);
   1261 			fdcpstatus(fdc);
   1262 		}
   1263 		bp->b_error = EIO;
   1264 		fdfinish(fd, bp);
   1265 	}
   1266 	fdc->sc_errors++;
   1267 }
   1268 
   1269 int
   1270 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
   1271 {
   1272 	struct fd_softc		*fd;
   1273 	struct disklabel	buffer;
   1274 	int			error;
   1275 	struct fdformat_parms	*form_parms;
   1276 	struct fdformat_cmd	*form_cmd;
   1277 	struct ne7_fd_formb	*fd_formb;
   1278 	unsigned int		scratch;
   1279 	int			il[FD_MAX_NSEC + 1];
   1280 	register int		i, j;
   1281 
   1282 	fd = device_lookup_private(&hdfd_cd, FDUNIT(dev));
   1283 
   1284 	switch (cmd) {
   1285 	case DIOCGDINFO:
   1286 		fdgetdisklabel(fd, dev);
   1287 		*(struct disklabel *)addr = *(fd->sc_dk.dk_label);
   1288 		return 0;
   1289 
   1290 	case DIOCGPART:
   1291 		fdgetdisklabel(fd, dev);
   1292 		((struct partinfo *)addr)->disklab = fd->sc_dk.dk_label;
   1293 		((struct partinfo *)addr)->part =
   1294 			      &fd->sc_dk.dk_label->d_partitions[RAW_PART];
   1295 		return 0;
   1296 
   1297 	case DIOCWLABEL:
   1298 		if ((flag & FWRITE) == 0)
   1299 			return EBADF;
   1300 		/* XXX do something */
   1301 		return 0;
   1302 
   1303 	case DIOCSDINFO:
   1304 	case DIOCWDINFO:
   1305 		if ((flag & FWRITE) == 0)
   1306 		    return EBADF;
   1307 
   1308 		fd->sc_flags &= ~FD_HAVELAB;   /* Invalid */
   1309 		error = setdisklabel(&buffer, (struct disklabel *)addr, 0,NULL);
   1310 		if (error)
   1311 		    return error;
   1312 
   1313 		if (cmd == DIOCWDINFO)
   1314 		    error = writedisklabel(dev, fdstrategy, &buffer, NULL);
   1315 		return error;
   1316 
   1317 	case FDIOCGETFORMAT:
   1318 		form_parms = (struct fdformat_parms *)addr;
   1319 		form_parms->fdformat_version = FDFORMAT_VERSION;
   1320 		form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
   1321 		form_parms->ncyl = fd->sc_type->tracks;
   1322 		form_parms->nspt = fd->sc_type->sectrac;
   1323 		form_parms->ntrk = fd->sc_type->heads;
   1324 		form_parms->stepspercyl = fd->sc_type->step;
   1325 		form_parms->gaplen = fd->sc_type->gap2;
   1326 		form_parms->fillbyte = fd->sc_type->fillbyte;
   1327 		form_parms->interleave = fd->sc_type->interleave;
   1328 		switch (fd->sc_type->rate) {
   1329 		case FDC_500KBPS:
   1330 			form_parms->xfer_rate = 500 * 1024;
   1331 			break;
   1332 		case FDC_300KBPS:
   1333 			form_parms->xfer_rate = 300 * 1024;
   1334 			break;
   1335 		case FDC_250KBPS:
   1336 			form_parms->xfer_rate = 250 * 1024;
   1337 			break;
   1338 		case FDC_125KBPS:
   1339 			form_parms->xfer_rate = 125 * 1024;
   1340 			break;
   1341 		default:
   1342 			return EINVAL;
   1343 		}
   1344 		return 0;
   1345 
   1346 	case FDIOCSETFORMAT:
   1347 		if ((flag & FWRITE) == 0)
   1348 			return EBADF;	/* must be opened for writing */
   1349 		form_parms = (struct fdformat_parms *)addr;
   1350 		if (form_parms->fdformat_version != FDFORMAT_VERSION)
   1351 			return EINVAL;	/* wrong version of formatting prog */
   1352 
   1353 		scratch = form_parms->nbps >> 7;
   1354 		if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
   1355 		    scratch & ~(1 << (ffs(scratch)-1)))
   1356 			/* not a power-of-two multiple of 128 */
   1357 			return EINVAL;
   1358 
   1359 		switch (form_parms->xfer_rate) {
   1360 		case 500 * 1024:
   1361 			fd->sc_type->rate = FDC_500KBPS;
   1362 			break;
   1363 		case 300 * 1024:
   1364 			fd->sc_type->rate = FDC_300KBPS;
   1365 			break;
   1366 		case 250 * 1024:
   1367 			fd->sc_type->rate = FDC_250KBPS;
   1368 			break;
   1369 		case 125 * 1024:
   1370 			fd->sc_type->rate = FDC_125KBPS;
   1371 			break;
   1372 		default:
   1373 			return EINVAL;
   1374 		}
   1375 
   1376 		if (form_parms->nspt > FD_MAX_NSEC ||
   1377 		    form_parms->fillbyte > 0xff ||
   1378 		    form_parms->interleave > 0xff)
   1379 			return EINVAL;
   1380 		fd->sc_type->sectrac = form_parms->nspt;
   1381 		if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
   1382 			return EINVAL;
   1383 		fd->sc_type->heads = form_parms->ntrk;
   1384 		fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
   1385 		fd->sc_type->secsize = ffs(scratch)-1;
   1386 		fd->sc_type->gap2 = form_parms->gaplen;
   1387 		fd->sc_type->tracks = form_parms->ncyl;
   1388 		fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
   1389 			form_parms->nbps / DEV_BSIZE;
   1390 		fd->sc_type->step = form_parms->stepspercyl;
   1391 		fd->sc_type->fillbyte = form_parms->fillbyte;
   1392 		fd->sc_type->interleave = form_parms->interleave;
   1393 		return 0;
   1394 
   1395 	case FDIOCFORMAT_TRACK:
   1396 		if ((flag & FWRITE) == 0)
   1397 			return EBADF;	/* must be opened for writing */
   1398 		form_cmd = (struct fdformat_cmd *)addr;
   1399 		if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
   1400 			return EINVAL;	/* wrong version of formatting prog */
   1401 
   1402 		if (form_cmd->head >= fd->sc_type->heads ||
   1403 		    form_cmd->cylinder >= fd->sc_type->tracks) {
   1404 			return EINVAL;
   1405 		}
   1406 
   1407 		fd_formb = malloc(sizeof(struct ne7_fd_formb),
   1408 		    M_TEMP, M_NOWAIT);
   1409 		if (fd_formb == 0)
   1410 			return ENOMEM;
   1411 
   1412 		fd_formb->head = form_cmd->head;
   1413 		fd_formb->cyl = form_cmd->cylinder;
   1414 		fd_formb->transfer_rate = fd->sc_type->rate;
   1415 		fd_formb->fd_formb_secshift = fd->sc_type->secsize;
   1416 		fd_formb->fd_formb_nsecs = fd->sc_type->sectrac;
   1417 		fd_formb->fd_formb_gaplen = fd->sc_type->gap2;
   1418 		fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte;
   1419 
   1420 		memset(il, 0,sizeof il);
   1421 		for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) {
   1422 			while (il[(j%fd_formb->fd_formb_nsecs)+1])
   1423 				j++;
   1424 			il[(j%fd_formb->fd_formb_nsecs)+1] = i;
   1425 			j += fd->sc_type->interleave;
   1426 		}
   1427 		for (i = 0; i < fd_formb->fd_formb_nsecs; i++) {
   1428 			fd_formb->fd_formb_cylno(i) = form_cmd->cylinder;
   1429 			fd_formb->fd_formb_headno(i) = form_cmd->head;
   1430 			fd_formb->fd_formb_secno(i) = il[i+1];
   1431 			fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize;
   1432 		}
   1433 
   1434 		error = fdformat(dev, fd_formb, l->l_proc);
   1435 		free(fd_formb, M_TEMP);
   1436 		return error;
   1437 
   1438 	case FDIOCGETOPTS:		/* get drive options */
   1439 		*(int *)addr = fd->sc_opts;
   1440 		return 0;
   1441 
   1442 	case FDIOCSETOPTS:		/* set drive options */
   1443 		fd->sc_opts = *(int *)addr;
   1444 		return 0;
   1445 
   1446 
   1447 	default:
   1448 		return ENOTTY;
   1449 	}
   1450 
   1451 #ifdef DIAGNOSTIC
   1452 	panic("fdioctl: impossible");
   1453 #endif
   1454 }
   1455 
   1456 int
   1457 fdformat(dev_t dev, struct ne7_fd_formb *finfo, struct proc *p)
   1458 {
   1459 	int rv = 0;
   1460 	struct fd_softc *fd = device_lookup_private(&hdfd_cd, FDUNIT(dev));
   1461 	struct fd_type *type = fd->sc_type;
   1462 	struct buf *bp;
   1463 
   1464 	/* set up a buffer header for fdstrategy() */
   1465 	bp = getiobuf(NULL, false);
   1466 	if (bp == NULL)
   1467 		return ENOBUFS;
   1468 	memset((void *)bp, 0, sizeof(struct buf));
   1469 	bp->b_flags = B_PHYS | B_FORMAT;
   1470 	bp->b_cflags |= BC_BUSY;
   1471 	bp->b_proc = p;
   1472 	bp->b_dev = dev;
   1473 
   1474 	/*
   1475 	 * calculate a fake blkno, so fdstrategy() would initiate a
   1476 	 * seek to the requested cylinder
   1477 	 */
   1478 	bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
   1479 		       + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
   1480 
   1481 	bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
   1482 	bp->b_data = (void *)finfo;
   1483 
   1484 #ifdef DEBUG
   1485 	printf("fdformat: blkno %x count %lx\n", bp->b_blkno, bp->b_bcount);
   1486 #endif
   1487 
   1488 	/* now do the format */
   1489 	fdstrategy(bp);
   1490 
   1491 	/* ...and wait for it to complete */
   1492 	mutex_enter(bp->b_objlock);
   1493 	while ((bp->b_oflags & BO_DONE) == 0) {
   1494 		rv = cv_timedwait(&bp->b_done, bp->b_objlock, 20 * hz);
   1495 		if (rv == EWOULDBLOCK)
   1496 			break;
   1497 	}
   1498 	mutex_exit(bp->b_objlock);
   1499 
   1500 	if (rv == EWOULDBLOCK) {
   1501 		/* timed out */
   1502 		rv = EIO;
   1503 		biodone(bp);
   1504 	} else if (bp->b_error != 0) {
   1505 		rv = bp->b_error;
   1506 	}
   1507 	putiobuf(bp);
   1508 	return rv;
   1509 }
   1510 
   1511 
   1512 /*
   1513  * Obtain a disklabel. Either a real one from the disk or, if there
   1514  * is none, a fake one.
   1515  */
   1516 static void
   1517 fdgetdisklabel(struct fd_softc *fd, dev_t dev)
   1518 {
   1519 	struct disklabel	*lp;
   1520 	struct cpu_disklabel	cpulab;
   1521 
   1522 	if (fd->sc_flags & FD_HAVELAB)
   1523 		return; /* Already got one */
   1524 
   1525 	lp   = fd->sc_dk.dk_label;
   1526 
   1527 	memset(lp, 0, sizeof(*lp));
   1528 	memset(&cpulab, 0, sizeof(cpulab));
   1529 
   1530 	lp->d_secpercyl  = fd->sc_type->seccyl;
   1531 	lp->d_type       = DTYPE_FLOPPY;
   1532 	lp->d_secsize    = FDC_BSIZE;
   1533 	lp->d_secperunit = fd->sc_type->size;
   1534 
   1535 	/*
   1536 	 * If there is no label on the disk: fake one
   1537 	 */
   1538 	if (readdisklabel(dev, fdstrategy, lp, &cpulab) != NULL)
   1539 		fdgetdefaultlabel(fd, lp, RAW_PART);
   1540 	fd->sc_flags |= FD_HAVELAB;
   1541 
   1542 	if ((FDC_BSIZE * fd->sc_type->size)
   1543 		< (lp->d_secsize * lp->d_secperunit)) {
   1544 		/*
   1545 		 * XXX: Ignore these fields. If you drop a vnddisk
   1546 		 *	on more than one floppy, you'll get disturbing
   1547 		 *	sounds!
   1548 		 */
   1549 		lp->d_secpercyl  = fd->sc_type->seccyl;
   1550 		lp->d_type       = DTYPE_FLOPPY;
   1551 		lp->d_secsize    = FDC_BSIZE;
   1552 		lp->d_secperunit = fd->sc_type->size;
   1553 	}
   1554 }
   1555 
   1556 /*
   1557  * Build defaultdisk label. For now we only create a label from what we
   1558  * know from 'sc'.
   1559  */
   1560 static void
   1561 fdgetdefaultlabel(struct fd_softc *fd, struct disklabel *lp, int part)
   1562 {
   1563 	memset(lp, 0, sizeof(struct disklabel));
   1564 
   1565 	lp->d_secsize     = 128 * (1 << fd->sc_type->secsize);
   1566 	lp->d_ntracks     = fd->sc_type->heads;
   1567 	lp->d_nsectors    = fd->sc_type->sectrac;
   1568 	lp->d_secpercyl   = lp->d_ntracks * lp->d_nsectors;
   1569 	lp->d_ncylinders  = fd->sc_type->size / lp->d_secpercyl;
   1570 	lp->d_secperunit  = fd->sc_type->size;
   1571 
   1572 	lp->d_type        = DTYPE_FLOPPY;
   1573 	lp->d_rpm         = 300; 	/* good guess I suppose.	*/
   1574 	lp->d_interleave  = 1;		/* FIXME: is this OK?		*/
   1575 	lp->d_bbsize      = 0;
   1576 	lp->d_sbsize      = 0;
   1577 	lp->d_npartitions = part + 1;
   1578 	lp->d_trkseek     = 6000; 	/* Who cares...			*/
   1579 	lp->d_magic       = DISKMAGIC;
   1580 	lp->d_magic2      = DISKMAGIC;
   1581 	lp->d_checksum    = dkcksum(lp);
   1582 	lp->d_partitions[part].p_size   = lp->d_secperunit;
   1583 	lp->d_partitions[part].p_fstype = FS_UNUSED;
   1584 	lp->d_partitions[part].p_fsize  = 1024;
   1585 	lp->d_partitions[part].p_frag   = 8;
   1586 }
   1587