xref: /netbsd-src/sys/arch/atari/dev/hdfd.c (revision 76dfffe33547c37f8bdd446e3e4ab0f3c16cea4b)
1 /*	$NetBSD: hdfd.c,v 1.2 1996/11/13 06:48:24 thorpej Exp $	*/
2 
3 /*-
4  * Copyright (c) 1996 Leo Weppelman
5  * Copyright (c) 1993, 1994, 1995, 1996
6  *	Charles M. Hannum.  All rights reserved.
7  * Copyright (c) 1990 The Regents of the University of California.
8  * All rights reserved.
9  *
10  * This code is derived from software contributed to Berkeley by
11  * Don Ahn.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. All advertising materials mentioning features or use of this software
22  *    must display the following acknowledgement:
23  *	This product includes software developed by the University of
24  *	California, Berkeley and its contributors.
25  * 4. Neither the name of the University nor the names of its contributors
26  *    may be used to endorse or promote products derived from this software
27  *    without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  *
41  *	@(#)fd.c	7.4 (Berkeley) 5/25/91
42  */
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/file.h>
48 #include <sys/ioctl.h>
49 #include <sys/device.h>
50 #include <sys/disklabel.h>
51 #include <sys/dkstat.h>
52 #include <sys/disk.h>
53 #include <sys/buf.h>
54 #include <sys/uio.h>
55 #include <sys/syslog.h>
56 #include <sys/queue.h>
57 #include <sys/conf.h>
58 #include <sys/device.h>
59 
60 #include <machine/cpu.h>
61 #include <machine/bus.h>
62 #include <machine/iomap.h>
63 #include <machine/mfp.h>
64 
65 #include <atari/dev/hdfdreg.h>
66 #include <atari/atari/device.h>
67 
68 /*
69  * {b,c}devsw[] function prototypes
70  */
71 dev_type_open(fdopen);
72 dev_type_close(fdclose);
73 dev_type_read(fdread);
74 dev_type_write(fdwrite);
75 dev_type_ioctl(fdioctl);
76 dev_type_size(fdsize);
77 dev_type_dump(fddump);
78 
79 volatile u_char	*fdio_addr;
80 
81 #define wrt_fdc_reg(reg, val)	{ fdio_addr[reg] = val; }
82 #define rd_fdc_reg(reg)		( fdio_addr[reg] )
83 
84 #define	fdc_ienable()		MFP2->mf_ierb |= IB_DCHG;
85 
86 /*
87  * Interface to the pseudo-dma handler
88  */
89 void	fddma_intr(void);
90 caddr_t	fddmaaddr  = NULL;
91 int	fddmalen   = 0;
92 
93 /*
94  * Argument to fdcintr.....
95  */
96 static void	*intr_arg = NULL; /* XXX: arg. to intr_establish() */
97 
98 
99 #define FDUNIT(dev)	(minor(dev) / 8)
100 #define FDTYPE(dev)	(minor(dev) % 8)
101 
102 #define b_cylin b_resid
103 
104 enum fdc_state {
105 	DEVIDLE = 0,
106 	MOTORWAIT,
107 	DOSEEK,
108 	SEEKWAIT,
109 	SEEKTIMEDOUT,
110 	SEEKCOMPLETE,
111 	DOIO,
112 	IOCOMPLETE,
113 	IOTIMEDOUT,
114 	DORESET,
115 	RESETCOMPLETE,
116 	RESETTIMEDOUT,
117 	DORECAL,
118 	RECALWAIT,
119 	RECALTIMEDOUT,
120 	RECALCOMPLETE,
121 };
122 
123 /* software state, per controller */
124 struct fdc_softc {
125 	struct device	sc_dev;		/* boilerplate */
126 	struct fd_softc	*sc_fd[4];	/* pointers to children */
127 	TAILQ_HEAD(drivehead, fd_softc) sc_drives;
128 	enum fdc_state	sc_state;
129 	int		sc_errors;	/* number of retries so far */
130 	int		sc_overruns;	/* number of overruns so far */
131 	u_char		sc_status[7];	/* copy of registers */
132 };
133 
134 /* controller driver configuration */
135 int	fdcprobe __P((struct device *, void *, void *));
136 int	fdprint __P((void *, const char *));
137 void	fdcattach __P((struct device *, struct device *, void *));
138 
139 struct cfattach fdc_ca = {
140 	sizeof(struct fdc_softc), fdcprobe, fdcattach
141 };
142 
143 struct cfdriver fdc_cd = {
144 	NULL, "fdc", DV_DULL
145 };
146 
147 /*
148  * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
149  * we tell them apart.
150  */
151 struct fd_type {
152 	int	sectrac;	/* sectors per track */
153 	int	heads;		/* number of heads */
154 	int	seccyl;		/* sectors per cylinder */
155 	int	secsize;	/* size code for sectors */
156 	int	datalen;	/* data len when secsize = 0 */
157 	int	steprate;	/* step rate and head unload time */
158 	int	gap1;		/* gap len between sectors */
159 	int	gap2;		/* formatting gap */
160 	int	tracks;		/* total num of tracks */
161 	int	size;		/* size of disk in sectors */
162 	int	step;		/* steps per cylinder */
163 	int	rate;		/* transfer speed code */
164 	char	*name;
165 };
166 
167 /*
168  * The order of entries in the following table is important -- BEWARE!
169  * The order of the types is the same as for the TT/Falcon....
170  */
171 struct fd_type fd_types[] = {
172         /* 360kB in 720kB drive */
173         {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_125KBPS, "360KB"  },
174         /* 3.5" 720kB diskette */
175         {  9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_125KBPS, "720KB"  },
176         /* 1.44MB diskette */
177         { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_250KBPS, "1.44MB" },
178 };
179 
180 /* software state, per disk (with up to 4 disks per ctlr) */
181 struct fd_softc {
182 	struct device	sc_dev;
183 	struct disk	sc_dk;
184 
185 	struct fd_type	*sc_deftype;	/* default type descriptor */
186 	struct fd_type	*sc_type;	/* current type descriptor */
187 
188 	daddr_t		sc_blkno;	/* starting block number */
189 	int		sc_bcount;	/* byte count left */
190 	int		sc_skip;	/* bytes already transferred */
191 	int		sc_nblks;	/* #blocks currently tranferring */
192 	int		sc_nbytes;	/* #bytes currently tranferring */
193 
194 	int		sc_drive;	/* physical unit number */
195 	int		sc_flags;
196 #define	FD_OPEN		0x01		/* it's open */
197 #define	FD_MOTOR	0x02		/* motor should be on */
198 #define	FD_MOTOR_WAIT	0x04		/* motor coming up */
199 	int		sc_cylin;	/* where we think the head is */
200 
201 	void		*sc_sdhook;	/* saved shutdown hook for drive. */
202 
203 	TAILQ_ENTRY(fd_softc) sc_drivechain;
204 	int		sc_ops;		/* I/O ops since last switch */
205 	struct buf	sc_q;		/* head of buf chain */
206 };
207 
208 /* floppy driver configuration */
209 int	fdprobe __P((struct device *, void *, void *));
210 void	fdattach __P((struct device *, struct device *, void *));
211 
212 struct cfattach hdfd_ca = {
213 	sizeof(struct fd_softc), fdprobe, fdattach
214 };
215 
216 struct cfdriver hdfd_cd = {
217 	NULL, "hdfd", DV_DISK
218 };
219 
220 void	fdstrategy __P((struct buf *));
221 void	fdstart __P((struct fd_softc *));
222 
223 struct dkdriver fddkdriver = { fdstrategy };
224 
225 void	fd_set_motor __P((struct fdc_softc *fdc, int reset));
226 void	fd_motor_off __P((void *arg));
227 void	fd_motor_on __P((void *arg));
228 int	fdcresult __P((struct fdc_softc *fdc));
229 int	out_fdc __P((u_char x));
230 void	fdc_ctrl_intr __P((struct clockframe *));
231 void	fdcstart __P((struct fdc_softc *fdc));
232 void	fdcstatus __P((struct device *dv, int n, char *s));
233 void	fdctimeout __P((void *arg));
234 void	fdcpseudointr __P((void *arg));
235 int	fdcintr __P((void *));
236 void	fdcretry __P((struct fdc_softc *fdc));
237 void	fdfinish __P((struct fd_softc *fd, struct buf *bp));
238 __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
239 
240 int
241 fdcprobe(parent, match, aux)
242 	struct device *parent;
243 	void *match, *aux;
244 {
245 	int		rv   = 0;
246 	struct cfdata	*cfp = match;
247 
248 	if(strcmp("fdc", aux) || cfp->cf_unit != 0)
249 		return(0);
250 
251 	if (!atari_realconfig)
252 		return 0;
253 
254 	if (bus_space_map(NULL, 0xfff00000, NBPG, 0, (caddr_t*)&fdio_addr)) {
255 		printf("fdcprobe: cannot map io-area\n");
256 		return (0);
257 	}
258 
259 #ifdef FD_DEBUG
260 	printf("fdcprobe: I/O mapping done va: %p\n", fdio_addr);
261 #endif
262 
263 	/* reset */
264 	wrt_fdc_reg(fdout, 0);
265 	delay(100);
266 	wrt_fdc_reg(fdout, FDO_FRST);
267 
268 	/* see if it can handle a command */
269 	if (out_fdc(NE7CMD_SPECIFY) < 0)
270 		goto out;
271 	out_fdc(0xdf);
272 	out_fdc(7);
273 
274 	rv = 1;
275 
276  out:
277 	if (rv == 0)
278 		bus_space_unmap(NULL, (caddr_t)fdio_addr, NBPG);
279 
280 	return rv;
281 }
282 
283 /*
284  * Arguments passed between fdcattach and fdprobe.
285  */
286 struct fdc_attach_args {
287 	int fa_drive;
288 	struct fd_type *fa_deftype;
289 };
290 
291 /*
292  * Print the location of a disk drive (called just before attaching the
293  * the drive).  If `fdc' is not NULL, the drive was found but was not
294  * in the system config file; print the drive name as well.
295  * Return QUIET (config_find ignores this if the device was configured) to
296  * avoid printing `fdN not configured' messages.
297  */
298 int
299 fdprint(aux, fdc)
300 	void *aux;
301 	const char *fdc;
302 {
303 	register struct fdc_attach_args *fa = aux;
304 
305 	if (!fdc)
306 		printf(" drive %d", fa->fa_drive);
307 	return QUIET;
308 }
309 
310 void
311 fdcattach(parent, self, aux)
312 	struct device *parent, *self;
313 	void *aux;
314 {
315 	struct fdc_softc	*fdc = (void *)self;
316 	struct fdc_attach_args	fa;
317 	int			has_fifo;
318 
319 	has_fifo = 0;
320 
321 	fdc->sc_state = DEVIDLE;
322 	TAILQ_INIT(&fdc->sc_drives);
323 
324 	out_fdc(NE7CMD_CONFIGURE);
325 	if (out_fdc(0) == 0) {
326 		out_fdc(0x1a);	/* No polling, fifo depth = 10	*/
327 		out_fdc(0);
328 
329 		/* Retain configuration across resets	*/
330 		out_fdc(NE7CMD_LOCK);
331 		(void)fdcresult(fdc);
332 		has_fifo = 1;
333 	}
334 	else {
335 		(void)rd_fdc_reg(fddata);
336 		printf(": no fifo");
337 	}
338 
339 	printf("\n");
340 
341 	/*
342 	 * Setup the interrupt vector.
343 	 * XXX: While no int_establish() functions are available,
344 	 *      we do it the Dirty(Tm) way...
345 	 */
346 	{
347 		extern	u_long	uservects[];
348 		extern	void	mfp_hdfd_nf(void), mfp_hdfd_fifo(void);
349 
350 		uservects[22] = (u_long)(has_fifo ? mfp_hdfd_fifo:mfp_hdfd_nf);
351 	}
352 
353 	/*
354 	 * Setup the interrupt logic.
355 	 */
356 	MFP2->mf_iprb &= ~IB_DCHG;
357 	MFP2->mf_imrb |= IB_DCHG;
358 	MFP2->mf_aer  |= 0x10; /* fdc int low->high */
359 
360 	/* physical limit: four drives per controller. */
361 	for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
362 		/*
363 		 * XXX: Choose something sensible as a default...
364 		 */
365 		fa.fa_deftype = &fd_types[2]; /* 1.44MB */
366 		(void)config_found(self, (void *)&fa, fdprint);
367 	}
368 }
369 
370 int
371 fdprobe(parent, match, aux)
372 	struct device *parent;
373 	void *match, *aux;
374 {
375 	struct fdc_softc	*fdc = (void *)parent;
376 	struct cfdata		*cf = match;
377 	struct fdc_attach_args	*fa = aux;
378 	int			drive = fa->fa_drive;
379 	int			n;
380 
381 	if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != drive)
382 		return 0;
383 	/*
384 	 * XXX
385 	 * This is to work around some odd interactions between this driver
386 	 * and SMC Ethernet cards.
387 	 */
388 	if (cf->cf_loc[0] == -1 && drive >= 2)
389 		return 0;
390 
391 	/* select drive and turn on motor */
392 	wrt_fdc_reg(fdout, drive | FDO_FRST | FDO_MOEN(drive));
393 
394 	/* wait for motor to spin up */
395 	delay(250000);
396 	out_fdc(NE7CMD_RECAL);
397 	out_fdc(drive);
398 
399 	/* wait for recalibrate */
400 	delay(2000000);
401 	out_fdc(NE7CMD_SENSEI);
402 	n = fdcresult(fdc);
403 
404 #ifdef FD_DEBUG
405 	{
406 		int i;
407 		printf("fdprobe: status");
408 		for (i = 0; i < n; i++)
409 			printf(" %x", fdc->sc_status[i]);
410 		printf("\n");
411 	}
412 #endif
413 	intr_arg = (void*)fdc;
414 	if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20)
415 		return 0;
416 	/* turn off motor */
417 	wrt_fdc_reg(fdout, FDO_FRST);
418 
419 	return 1;
420 }
421 
422 /*
423  * Controller is working, and drive responded.  Attach it.
424  */
425 void
426 fdattach(parent, self, aux)
427 	struct device *parent, *self;
428 	void *aux;
429 {
430 	struct fdc_softc	*fdc  = (void *)parent;
431 	struct fd_softc		*fd   = (void *)self;
432 	struct fdc_attach_args	*fa   = aux;
433 	struct fd_type		*type = fa->fa_deftype;
434 	int			drive = fa->fa_drive;
435 
436 	/* XXX Allow `flags' to override device type? */
437 
438 	if (type)
439 		printf(": %s %d cyl, %d head, %d sec\n", type->name,
440 		    type->tracks, type->heads, type->sectrac);
441 	else
442 		printf(": density unknown\n");
443 
444 	fd->sc_cylin      = -1;
445 	fd->sc_drive      = drive;
446 	fd->sc_deftype    = type;
447 	fdc->sc_fd[drive] = fd;
448 
449 	/*
450 	 * Initialize and attach the disk structure.
451 	 */
452 	fd->sc_dk.dk_name   = fd->sc_dev.dv_xname;
453 	fd->sc_dk.dk_driver = &fddkdriver;
454 	disk_attach(&fd->sc_dk);
455 
456 	/* XXX Need to do some more fiddling with sc_dk. */
457 	dk_establish(&fd->sc_dk, &fd->sc_dev);
458 
459 	/* Needed to power off if the motor is on when we halt. */
460 	fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd);
461 }
462 
463 /*
464  * This is called from the assembly part of the interrupt handler
465  * when it is clear that the interrupt was not related to shoving
466  * data.
467  */
468 void
469 fdc_ctrl_intr(frame)
470 	register struct clockframe *frame;
471 {
472 	int	s;
473 
474 	/*
475 	 * Disable further interrupts. The fdcintr() routine
476 	 * explicitely enables them when needed.
477 	 */
478 	MFP2->mf_ierb &= ~IB_DCHG;
479 
480 	/*
481 	 * Set fddmalen to zero so no pseudo-dma transfers will
482 	 * occur.
483 	 */
484 	fddmalen = 0;
485 
486 	if (!BASEPRI(frame->sr)) {
487 		/*
488 		 * We don't want to stay on ipl6.....
489 		 */
490 		add_sicallback((si_farg)fdcpseudointr, intr_arg, 0);
491 	}
492 	else {
493 		s = splbio();
494 		(void) fdcintr(intr_arg);
495 		splx(s);
496 	}
497 }
498 
499 __inline struct fd_type *
500 fd_dev_to_type(fd, dev)
501 	struct fd_softc *fd;
502 	dev_t dev;
503 {
504 	int type = FDTYPE(dev);
505 
506 	if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
507 		return NULL;
508 	return type ? &fd_types[type - 1] : fd->sc_deftype;
509 }
510 
511 void
512 fdstrategy(bp)
513 	register struct buf *bp;	/* IO operation to perform */
514 {
515 	struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(bp->b_dev)];
516 	int sz;
517  	int s;
518 
519 	/* Valid unit, controller, and request? */
520 	if (bp->b_blkno < 0 ||
521 	    (bp->b_bcount % FDC_BSIZE) != 0) {
522 		bp->b_error = EINVAL;
523 		goto bad;
524 	}
525 
526 	/* If it's a null transfer, return immediately. */
527 	if (bp->b_bcount == 0)
528 		goto done;
529 
530 	sz = howmany(bp->b_bcount, FDC_BSIZE);
531 
532 	if (bp->b_blkno + sz > fd->sc_type->size) {
533 		sz = fd->sc_type->size - bp->b_blkno;
534 		if (sz == 0) {
535 			/* If exactly at end of disk, return EOF. */
536 			goto done;
537 		}
538 		if (sz < 0) {
539 			/* If past end of disk, return EINVAL. */
540 			bp->b_error = EINVAL;
541 			goto bad;
542 		}
543 		/* Otherwise, truncate request. */
544 		bp->b_bcount = sz << DEV_BSHIFT;
545 	}
546 
547  	bp->b_cylin = bp->b_blkno / (FDC_BSIZE/DEV_BSIZE) / fd->sc_type->seccyl;
548 
549 #ifdef FD_DEBUG
550 	printf("fdstrategy: b_blkno %d b_bcount %ld blkno %ld cylin %ld sz"
551 		" %d\n", bp->b_blkno, bp->b_bcount, (long)fd->sc_blkno,
552 		bp->b_cylin, sz);
553 #endif
554 
555 	/* Queue transfer on drive, activate drive and controller if idle. */
556 	s = splbio();
557 	disksort(&fd->sc_q, bp);
558 	untimeout(fd_motor_off, fd); /* a good idea */
559 	if (!fd->sc_q.b_active)
560 		fdstart(fd);
561 #ifdef DIAGNOSTIC
562 	else {
563 		struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
564 		if (fdc->sc_state == DEVIDLE) {
565 			printf("fdstrategy: controller inactive\n");
566 			fdcstart(fdc);
567 		}
568 	}
569 #endif
570 	splx(s);
571 	return;
572 
573 bad:
574 	bp->b_flags |= B_ERROR;
575 done:
576 	/* Toss transfer; we're done early. */
577 	bp->b_resid = bp->b_bcount;
578 	biodone(bp);
579 }
580 
581 void
582 fdstart(fd)
583 	struct fd_softc *fd;
584 {
585 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
586 	int active = fdc->sc_drives.tqh_first != 0;
587 
588 	/* Link into controller queue. */
589 	fd->sc_q.b_active = 1;
590 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
591 
592 	/* If controller not already active, start it. */
593 	if (!active)
594 		fdcstart(fdc);
595 }
596 
597 void
598 fdfinish(fd, bp)
599 	struct fd_softc *fd;
600 	struct buf *bp;
601 {
602 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
603 
604 	/*
605 	 * Move this drive to the end of the queue to give others a `fair'
606 	 * chance.  We only force a switch if N operations are completed while
607 	 * another drive is waiting to be serviced, since there is a long motor
608 	 * startup delay whenever we switch.
609 	 */
610 	if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
611 		fd->sc_ops = 0;
612 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
613 		if (bp->b_actf) {
614 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
615 		} else
616 			fd->sc_q.b_active = 0;
617 	}
618 	bp->b_resid = fd->sc_bcount;
619 	fd->sc_skip = 0;
620 	fd->sc_q.b_actf = bp->b_actf;
621 
622 	biodone(bp);
623 	/* turn off motor 5s from now */
624 	timeout(fd_motor_off, fd, 5 * hz);
625 	fdc->sc_state = DEVIDLE;
626 }
627 
628 int
629 fdread(dev, uio, flags)
630 	dev_t dev;
631 	struct uio *uio;
632 	int flags;
633 {
634 	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
635 }
636 
637 int
638 fdwrite(dev, uio, flags)
639 	dev_t dev;
640 	struct uio *uio;
641 	int flags;
642 {
643 	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
644 }
645 
646 void
647 fd_set_motor(fdc, reset)
648 	struct fdc_softc *fdc;
649 	int reset;
650 {
651 	struct fd_softc *fd;
652 	u_char status;
653 	int n;
654 
655 	if ((fd = fdc->sc_drives.tqh_first) != NULL)
656 		status = fd->sc_drive;
657 	else
658 		status = 0;
659 	if (!reset)
660 		status |= FDO_FRST | FDO_FDMAEN;
661 	for (n = 0; n < 4; n++)
662 		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
663 			status |= FDO_MOEN(n);
664 	wrt_fdc_reg(fdout, status);
665 }
666 
667 void
668 fd_motor_off(arg)
669 	void *arg;
670 {
671 	struct fd_softc *fd = arg;
672 	int s;
673 
674 	s = splbio();
675 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
676 	fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0);
677 	splx(s);
678 }
679 
680 void
681 fd_motor_on(arg)
682 	void *arg;
683 {
684 	struct fd_softc *fd = arg;
685 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
686 	int s;
687 
688 	s = splbio();
689 	fd->sc_flags &= ~FD_MOTOR_WAIT;
690 	if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
691 		(void) fdcintr(fdc);
692 	splx(s);
693 }
694 
695 int
696 fdcresult(fdc)
697 	struct fdc_softc *fdc;
698 {
699 	u_char i;
700 	int j = 100000,
701 	    n = 0;
702 
703 	for (; j; j--) {
704 		i = rd_fdc_reg(fdsts) & (NE7_DIO | NE7_RQM | NE7_CB);
705 		if (i == NE7_RQM)
706 			return n;
707 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
708 			if (n >= sizeof(fdc->sc_status)) {
709 				log(LOG_ERR, "fdcresult: overrun\n");
710 				return -1;
711 			}
712 			fdc->sc_status[n++] = rd_fdc_reg(fddata);
713 		}
714 	}
715 	log(LOG_ERR, "fdcresult: timeout\n");
716 	return -1;
717 }
718 
719 int
720 out_fdc(x)
721 	u_char x;
722 {
723 	int i = 100000;
724 
725 	while ((rd_fdc_reg(fdsts) & NE7_RQM) == 0 && i-- > 0);
726 	if (i <= 0)
727 		return -1;
728 	while ((rd_fdc_reg(fdsts) & NE7_DIO) && i-- > 0);
729 	if (i <= 0)
730 		return -1;
731 	wrt_fdc_reg(fddata, x);
732 	return 0;
733 }
734 
735 int
736 fdopen(dev, flags, mode, p)
737 	dev_t dev;
738 	int flags;
739 	int mode;
740 	struct proc *p;
741 {
742  	int unit;
743 	struct fd_softc *fd;
744 	struct fd_type *type;
745 
746 	unit = FDUNIT(dev);
747 	if (unit >= hdfd_cd.cd_ndevs)
748 		return ENXIO;
749 	fd = hdfd_cd.cd_devs[unit];
750 	if (fd == 0)
751 		return ENXIO;
752 	type = fd_dev_to_type(fd, dev);
753 	if (type == NULL)
754 		return ENXIO;
755 
756 	if ((fd->sc_flags & FD_OPEN) != 0 &&
757 	    fd->sc_type != type)
758 		return EBUSY;
759 
760 	fd->sc_type = type;
761 	fd->sc_cylin = -1;
762 	fd->sc_flags |= FD_OPEN;
763 
764 	return 0;
765 }
766 
767 int
768 fdclose(dev, flags, mode, p)
769 	dev_t dev;
770 	int flags;
771 	int mode;
772 	struct proc *p;
773 {
774 	struct fd_softc *fd = hdfd_cd.cd_devs[FDUNIT(dev)];
775 
776 	fd->sc_flags &= ~FD_OPEN;
777 	return 0;
778 }
779 
780 void
781 fdcstart(fdc)
782 	struct fdc_softc *fdc;
783 {
784 
785 #ifdef DIAGNOSTIC
786 	/* only got here if controller's drive queue was inactive; should
787 	   be in idle state */
788 	if (fdc->sc_state != DEVIDLE) {
789 		printf("fdcstart: not idle\n");
790 		return;
791 	}
792 #endif
793 	(void) fdcintr(fdc);
794 }
795 
796 void
797 fdcstatus(dv, n, s)
798 	struct device *dv;
799 	int n;
800 	char *s;
801 {
802 	struct fdc_softc *fdc = (void *)dv->dv_parent;
803 	char bits[64];
804 
805 	if (n == 0) {
806 		out_fdc(NE7CMD_SENSEI);
807 		(void) fdcresult(fdc);
808 		n = 2;
809 	}
810 
811 	printf("%s: %s", dv->dv_xname, s);
812 
813 	switch (n) {
814 	case 0:
815 		printf("\n");
816 		break;
817 	case 2:
818 		printf(" (st0 %s cyl %d)\n",
819 		    bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
820 		    bits, sizeof(bits)), fdc->sc_status[1]);
821 		break;
822 	case 7:
823 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
824 		    NE7_ST0BITS, bits, sizeof(bits)));
825 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
826 		    NE7_ST1BITS, bits, sizeof(bits)));
827 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
828 		    NE7_ST2BITS, bits, sizeof(bits)));
829 		printf(" cyl %d head %d sec %d)\n",
830 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
831 		break;
832 #ifdef DIAGNOSTIC
833 	default:
834 		printf("\nfdcstatus: weird size");
835 		break;
836 #endif
837 	}
838 }
839 
840 void
841 fdctimeout(arg)
842 	void *arg;
843 {
844 	struct fdc_softc *fdc = arg;
845 	struct fd_softc *fd = fdc->sc_drives.tqh_first;
846 	int s;
847 
848 	s = splbio();
849 	fdcstatus(&fd->sc_dev, 0, "timeout");
850 
851 	if (fd->sc_q.b_actf)
852 		fdc->sc_state++;
853 	else
854 		fdc->sc_state = DEVIDLE;
855 
856 	(void) fdcintr(fdc);
857 	splx(s);
858 }
859 
860 void
861 fdcpseudointr(arg)
862 	void *arg;
863 {
864 	int s;
865 
866 	/* Just ensure it has the right spl. */
867 	s = splbio();
868 	(void) fdcintr(arg);
869 	splx(s);
870 }
871 
872 int
873 fdcintr(arg)
874 	void *arg;
875 {
876 	struct fdc_softc *fdc = arg;
877 #define	st0	fdc->sc_status[0]
878 #define	st1	fdc->sc_status[1]
879 #define	cyl	fdc->sc_status[1]
880 	struct fd_softc	*fd;
881 	struct buf	*bp;
882 	int		read, head, sec, i, nblks;
883 	struct fd_type	*type;
884 
885 loop:
886 	/* Is there a drive for the controller to do a transfer with? */
887 	fd = fdc->sc_drives.tqh_first;
888 	if (fd == NULL) {
889 		fdc->sc_state = DEVIDLE;
890  		return 1;
891 	}
892 
893 	/* Is there a transfer to this drive?  If not, deactivate drive. */
894 	bp = fd->sc_q.b_actf;
895 	if (bp == NULL) {
896 		fd->sc_ops = 0;
897 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
898 		fd->sc_q.b_active = 0;
899 		goto loop;
900 	}
901 
902 	switch (fdc->sc_state) {
903 	case DEVIDLE:
904 		fdc->sc_errors = 0;
905 		fdc->sc_overruns = 0;
906 		fd->sc_skip = 0;
907 		fd->sc_bcount = bp->b_bcount;
908 		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
909 		untimeout(fd_motor_off, fd);
910 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
911 			fdc->sc_state = MOTORWAIT;
912 			return 1;
913 		}
914 		if ((fd->sc_flags & FD_MOTOR) == 0) {
915 			/* Turn on the motor, being careful about pairing. */
916 			struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
917 			if (ofd && ofd->sc_flags & FD_MOTOR) {
918 				untimeout(fd_motor_off, ofd);
919 				ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
920 			}
921 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
922 			fd_set_motor(fdc, 0);
923 			fdc->sc_state = MOTORWAIT;
924 			/* Allow .25s for motor to stabilize. */
925 			timeout(fd_motor_on, fd, hz / 4);
926 			return 1;
927 		}
928 		/* Make sure the right drive is selected. */
929 		fd_set_motor(fdc, 0);
930 
931 		/* fall through */
932 	case DOSEEK:
933 	doseek:
934 		if (fd->sc_cylin == bp->b_cylin)
935 			goto doio;
936 
937 		out_fdc(NE7CMD_SPECIFY);/* specify command */
938 		out_fdc(fd->sc_type->steprate);
939 		out_fdc(0x7);	/* XXX head load time == 6ms - non-dma */
940 
941 		fdc_ienable();
942 
943 		out_fdc(NE7CMD_SEEK);	/* seek function */
944 		out_fdc(fd->sc_drive);	/* drive number */
945 		out_fdc(bp->b_cylin * fd->sc_type->step);
946 
947 		fd->sc_cylin = -1;
948 		fdc->sc_state = SEEKWAIT;
949 
950 		fd->sc_dk.dk_seek++;
951 		disk_busy(&fd->sc_dk);
952 
953 		timeout(fdctimeout, fdc, 4 * hz);
954 		return 1;
955 
956 	case DOIO:
957 	doio:
958 		type  = fd->sc_type;
959 		sec   = fd->sc_blkno % type->seccyl;
960 		head  = sec / type->sectrac;
961 		sec  -= head * type->sectrac;
962 		nblks = type->sectrac - sec;
963 		nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
964 		nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
965 		fd->sc_nblks  = nblks;
966 		fd->sc_nbytes = nblks * FDC_BSIZE;
967 #ifdef DIAGNOSTIC
968 		{
969 		     int block;
970 
971 		     block = (fd->sc_cylin * type->heads + head)
972 				* type->sectrac + sec;
973 		     if (block != fd->sc_blkno) {
974 			 printf("fdcintr: block %d != blkno %d\n",
975 						block, fd->sc_blkno);
976 #ifdef DDB
977 			 Debugger();
978 #endif
979 		     }
980 		}
981 #endif
982 		read = bp->b_flags & B_READ ? 1 : 0;
983 
984 		/*
985 		 * Setup pseudo-dma address & count
986 		 */
987 		fddmaaddr = bp->b_data + fd->sc_skip;
988 		fddmalen  = fd->sc_nbytes;
989 
990 		wrt_fdc_reg(fdctl, type->rate);
991 #ifdef FD_DEBUG
992 		printf("fdcintr: %s drive %d track %d head %d sec %d"
993 			" nblks %d\n", read ? "read" : "write",
994 			fd->sc_drive, fd->sc_cylin, head, sec, nblks);
995 #endif
996 		fdc_ienable();
997 
998 		if (read)
999 			out_fdc(NE7CMD_READ);	/* READ */
1000 		else
1001 			out_fdc(NE7CMD_WRITE);	/* WRITE */
1002 		out_fdc((head << 2) | fd->sc_drive);
1003 		out_fdc(fd->sc_cylin);		/* track	 */
1004 		out_fdc(head);			/* head		 */
1005 		out_fdc(sec + 1);		/* sector +1	 */
1006 		out_fdc(type->secsize);	/* sector size   */
1007 		out_fdc(sec + nblks);		/* last sectors	 */
1008 		out_fdc(type->gap1);		/* gap1 size	 */
1009 		out_fdc(type->datalen);	/* data length	 */
1010 		fdc->sc_state = IOCOMPLETE;
1011 
1012 		disk_busy(&fd->sc_dk);
1013 
1014 		/* allow 2 seconds for operation */
1015 		timeout(fdctimeout, fdc, 2 * hz);
1016 		return 1;				/* will return later */
1017 
1018 	case SEEKWAIT:
1019 		untimeout(fdctimeout, fdc);
1020 		fdc->sc_state = SEEKCOMPLETE;
1021 		/* allow 1/50 second for heads to settle */
1022 		timeout(fdcpseudointr, fdc, hz / 50);
1023 		return 1;
1024 
1025 	case SEEKCOMPLETE:
1026 		disk_unbusy(&fd->sc_dk, 0);	/* no data on seek */
1027 
1028 		/* Make sure seek really happened. */
1029 		out_fdc(NE7CMD_SENSEI);
1030 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
1031 		    cyl != bp->b_cylin * fd->sc_type->step) {
1032 #ifdef FD_DEBUG
1033 			fdcstatus(&fd->sc_dev, 2, "seek failed");
1034 #endif
1035 			fdcretry(fdc);
1036 			goto loop;
1037 		}
1038 		fd->sc_cylin = bp->b_cylin;
1039 		goto doio;
1040 
1041 	case IOTIMEDOUT:
1042 	case SEEKTIMEDOUT:
1043 	case RECALTIMEDOUT:
1044 	case RESETTIMEDOUT:
1045 		fdcretry(fdc);
1046 		goto loop;
1047 
1048 	case IOCOMPLETE: /* IO DONE, post-analyze */
1049 		untimeout(fdctimeout, fdc);
1050 
1051 		disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid));
1052 
1053 		if (fdcresult(fdc) != 7 || (st1 & 0x37) != 0) {
1054 			/*
1055 			 * As the damn chip doesn't seem to have a FIFO,
1056 			 * accept a few overruns as a fact of life *sigh*
1057 			 */
1058 			if ((st1 & 0x10) && (++fdc->sc_overruns < 4)) {
1059 				fdc->sc_state = DOSEEK;
1060 				goto loop;
1061 			}
1062 #ifdef FD_DEBUG
1063 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1064 			    "read failed" : "write failed");
1065 			printf("blkno %d nblks %d\n",
1066 			    fd->sc_blkno, fd->sc_nblks);
1067 #endif
1068 			fdcretry(fdc);
1069 			goto loop;
1070 		}
1071 		if (fdc->sc_errors) {
1072 			diskerr(bp, "fd", "soft error", LOG_PRINTF,
1073 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1074 			printf("\n");
1075 			fdc->sc_errors = 0;
1076 		}
1077 		fdc->sc_overruns = 0;
1078 		fd->sc_blkno += fd->sc_nblks;
1079 		fd->sc_skip += fd->sc_nbytes;
1080 		fd->sc_bcount -= fd->sc_nbytes;
1081 		if (fd->sc_bcount > 0) {
1082 			bp->b_cylin = fd->sc_blkno / fd->sc_type->seccyl;
1083 			goto doseek;
1084 		}
1085 		fdfinish(fd, bp);
1086 		goto loop;
1087 
1088 	case DORESET:
1089 		/* try a reset, keep motor on */
1090 		fd_set_motor(fdc, 1);
1091 		delay(100);
1092 		fd_set_motor(fdc, 0);
1093 		fdc->sc_state = RESETCOMPLETE;
1094 		timeout(fdctimeout, fdc, hz / 2);
1095 		return 1;			/* will return later */
1096 
1097 	case RESETCOMPLETE:
1098 		untimeout(fdctimeout, fdc);
1099 		/* clear the controller output buffer */
1100 		for (i = 0; i < 4; i++) {
1101 			out_fdc(NE7CMD_SENSEI);
1102 			(void) fdcresult(fdc);
1103 		}
1104 
1105 		/* fall through */
1106 	case DORECAL:
1107 		fdc_ienable();
1108 
1109 		out_fdc(NE7CMD_RECAL);	/* recalibrate function */
1110 		out_fdc(fd->sc_drive);
1111 		fdc->sc_state = RECALWAIT;
1112 		timeout(fdctimeout, fdc, 5 * hz);
1113 		return 1;			/* will return later */
1114 
1115 	case RECALWAIT:
1116 		untimeout(fdctimeout, fdc);
1117 		fdc->sc_state = RECALCOMPLETE;
1118 		/* allow 1/30 second for heads to settle */
1119 		timeout(fdcpseudointr, fdc, hz / 30);
1120 		return 1;			/* will return later */
1121 
1122 	case RECALCOMPLETE:
1123 		out_fdc(NE7CMD_SENSEI);
1124 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1125 #ifdef FD_DEBUG
1126 			fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1127 #endif
1128 			fdcretry(fdc);
1129 			goto loop;
1130 		}
1131 		fd->sc_cylin = 0;
1132 		goto doseek;
1133 
1134 	case MOTORWAIT:
1135 		if (fd->sc_flags & FD_MOTOR_WAIT)
1136 			return 1;		/* time's not up yet */
1137 		goto doseek;
1138 
1139 	default:
1140 		fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1141 		return 1;
1142 	}
1143 #ifdef DIAGNOSTIC
1144 	panic("fdcintr: impossible");
1145 #endif
1146 #undef	st0
1147 #undef	st1
1148 #undef	cyl
1149 }
1150 
1151 void
1152 fdcretry(fdc)
1153 	struct fdc_softc *fdc;
1154 {
1155 	char bits[64];
1156 	struct fd_softc *fd;
1157 	struct buf *bp;
1158 
1159 	fd = fdc->sc_drives.tqh_first;
1160 	bp = fd->sc_q.b_actf;
1161 
1162 	switch (fdc->sc_errors) {
1163 	case 0:
1164 		/* try again */
1165 		fdc->sc_state = DOSEEK;
1166 		break;
1167 
1168 	case 1: case 2: case 3:
1169 		/* didn't work; try recalibrating */
1170 		fdc->sc_state = DORECAL;
1171 		break;
1172 
1173 	case 4:
1174 		/* still no go; reset the bastard */
1175 		fdc->sc_state = DORESET;
1176 		break;
1177 
1178 	default:
1179 		diskerr(bp, "fd", "hard error", LOG_PRINTF,
1180 		    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1181 
1182 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1183 		    NE7_ST0BITS, bits, sizeof(bits)));
1184 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1185 		    NE7_ST1BITS, bits, sizeof(bits)));
1186 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1187 		    NE7_ST2BITS, bits, sizeof(bits)));
1188 		printf(" cyl %d head %d sec %d)\n",
1189 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
1190 
1191 		bp->b_flags |= B_ERROR;
1192 		bp->b_error = EIO;
1193 		fdfinish(fd, bp);
1194 	}
1195 	fdc->sc_errors++;
1196 }
1197 
1198 int
1199 fdsize(dev)
1200 	dev_t dev;
1201 {
1202 
1203 	/* Swapping to floppies would not make sense. */
1204 	return -1;
1205 }
1206 
1207 int
1208 fddump(dev, blkno, va, size)
1209 	dev_t dev;
1210 	daddr_t blkno;
1211 	caddr_t va;
1212 	size_t size;
1213 {
1214 
1215 	/* Not implemented. */
1216 	return ENXIO;
1217 }
1218 
1219 int
1220 fdioctl(dev, cmd, addr, flag, p)
1221 	dev_t dev;
1222 	u_long cmd;
1223 	caddr_t addr;
1224 	int flag;
1225 	struct proc *p;
1226 {
1227 	struct fd_softc		*fd;
1228 	struct disklabel	buffer;
1229 	struct cpu_disklabel	cpulab;
1230 	int error;
1231 
1232 	fd = hdfd_cd.cd_devs[FDUNIT(dev)];
1233 
1234 	switch (cmd) {
1235 	case DIOCGDINFO:
1236 		bzero(&buffer, sizeof(buffer));
1237 		bzero(&cpulab, sizeof(cpulab));
1238 
1239 		buffer.d_secpercyl  = fd->sc_type->seccyl;
1240 		buffer.d_type       = DTYPE_FLOPPY;
1241 		buffer.d_secsize    = FDC_BSIZE;
1242 		buffer.d_secperunit = fd->sc_type->size;
1243 
1244 		if (readdisklabel(dev, fdstrategy, &buffer, &cpulab) != NULL)
1245 			return EINVAL;
1246 		*(struct disklabel *)addr = buffer;
1247 		return 0;
1248 
1249 	case DIOCWLABEL:
1250 		if ((flag & FWRITE) == 0)
1251 			return EBADF;
1252 		/* XXX do something */
1253 		return 0;
1254 
1255 	case DIOCWDINFO:
1256 		if ((flag & FWRITE) == 0)
1257 			return EBADF;
1258 
1259 		error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
1260 		if (error)
1261 			return error;
1262 
1263 		error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1264 		return error;
1265 
1266 	default:
1267 		return ENOTTY;
1268 	}
1269 
1270 #ifdef DIAGNOSTIC
1271 	panic("fdioctl: impossible");
1272 #endif
1273 }
1274