xref: /openbsd/sys/dev/isa/fd.c (revision 78b63d65)
1 /*	$OpenBSD: fd.c,v 1.43 2001/10/26 01:28:06 nate Exp $	*/
2 /*	$NetBSD: fd.c,v 1.90 1996/05/12 23:12:03 mycroft Exp $	*/
3 
4 /*-
5  * Copyright (c) 1993, 1994, 1995, 1996 Charles Hannum.
6  * Copyright (c) 1990 The Regents of the University of California.
7  * All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * Don Ahn.
11  *
12  * Portions Copyright (c) 1993, 1994 by
13  *  jc@irbs.UUCP (John Capo)
14  *  vak@zebub.msk.su (Serge Vakulenko)
15  *  ache@astral.msk.su (Andrew A. Chernov)
16  *  joerg_wunsch@uriah.sax.de (Joerg Wunsch)
17  *
18  * Redistribution and use in source and binary forms, with or without
19  * modification, are permitted provided that the following conditions
20  * are met:
21  * 1. Redistributions of source code must retain the above copyright
22  *    notice, this list of conditions and the following disclaimer.
23  * 2. Redistributions in binary form must reproduce the above copyright
24  *    notice, this list of conditions and the following disclaimer in the
25  *    documentation and/or other materials provided with the distribution.
26  * 3. All advertising materials mentioning features or use of this software
27  *    must display the following acknowledgement:
28  *	This product includes software developed by the University of
29  *	California, Berkeley and its contributors.
30  * 4. Neither the name of the University nor the names of its contributors
31  *    may be used to endorse or promote products derived from this software
32  *    without specific prior written permission.
33  *
34  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
35  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44  * SUCH DAMAGE.
45  *
46  *	@(#)fd.c	7.4 (Berkeley) 5/25/91
47  */
48 
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/kernel.h>
52 #include <sys/file.h>
53 #include <sys/ioctl.h>
54 #include <sys/device.h>
55 #include <sys/disklabel.h>
56 #include <sys/dkstat.h>
57 #include <sys/disk.h>
58 #include <sys/buf.h>
59 #include <sys/malloc.h>
60 #include <sys/uio.h>
61 #include <sys/mtio.h>
62 #include <sys/proc.h>
63 #include <sys/syslog.h>
64 #include <sys/queue.h>
65 #include <sys/timeout.h>
66 
67 #include <machine/cpu.h>
68 #include <machine/bus.h>
69 #include <machine/conf.h>
70 #include <machine/intr.h>
71 #include <machine/ioctl_fd.h>
72 
73 #include <dev/isa/isavar.h>
74 #include <dev/isa/isadmavar.h>
75 #include <dev/isa/fdreg.h>
76 
77 #if defined(i386)
78 #include <i386/isa/nvram.h>
79 #endif
80 
81 #include <dev/isa/fdlink.h>
82 
83 /* XXX misuse a flag to identify format operation */
84 #define B_FORMAT B_XXX
85 
86 #define b_cylin b_resid
87 
88 /* fd_type struct now in ioctl_fd.h */
89 
90 /* The order of entries in the following table is important -- BEWARE! */
91 struct fd_type fd_types[] = {
92         { 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,"1.44MB"    }, /* 1.44MB diskette */
93         { 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS, "1.2MB"    }, /* 1.2 MB AT-diskettes */
94         {  9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS, "360KB/AT" }, /* 360kB in 1.2MB drive */
95         {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS, "360KB/PC" }, /* 360kB PC diskettes */
96         {  9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS, "720KB"    }, /* 3.5" 720kB diskette */
97         {  9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS, "720KB/x"  }, /* 720kB in 1.2MB drive */
98         {  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS, "360KB/x"  }, /* 360kB in 720kB drive */
99 	{ 36,2,72,2,0xff,0xaf,0x1b,0x54,80,5760,1,FDC_500KBPS,"2.88MB"    },  /* 2.88MB diskette */
100 	{  8,2,16,3,0xff,0xdf,0x35,0x74,77,1232,1,FDC_500KBPS,"1.2MB/[1024bytes/sector]" }	/* 1.2 MB japanese format */
101 };
102 
103 /* software state, per disk (with up to 4 disks per ctlr) */
104 struct fd_softc {
105 	struct device sc_dev;
106 	struct disk sc_dk;
107 
108 	struct fd_type *sc_deftype;	/* default type descriptor */
109 	struct fd_type *sc_type;	/* current type descriptor */
110 
111 	daddr_t	sc_blkno;	/* starting block number */
112 	int sc_bcount;		/* byte count left */
113  	int sc_opts;			/* user-set options */
114 	int sc_skip;		/* bytes already transferred */
115 	int sc_nblks;		/* number of blocks currently tranferring */
116 	int sc_nbytes;		/* number of bytes currently tranferring */
117 
118 	int sc_drive;		/* physical unit number */
119 	int sc_flags;
120 #define	FD_OPEN		0x01		/* it's open */
121 #define	FD_MOTOR	0x02		/* motor should be on */
122 #define	FD_MOTOR_WAIT	0x04		/* motor coming up */
123 	int sc_cylin;		/* where we think the head is */
124 
125 	void *sc_sdhook;	/* saved shutdown hook for drive. */
126 
127 	TAILQ_ENTRY(fd_softc) sc_drivechain;
128 	int sc_ops;		/* I/O ops since last switch */
129 	struct buf sc_q;	/* head of buf chain */
130 	struct timeout fd_motor_on_to;
131 	struct timeout fd_motor_off_to;
132 	struct timeout fdtimeout_to;
133 };
134 
135 /* floppy driver configuration */
136 int fdprobe __P((struct device *, void *, void *));
137 void fdattach __P((struct device *, struct device *, void *));
138 
139 struct cfattach fd_ca = {
140 	sizeof(struct fd_softc), fdprobe, fdattach
141 };
142 
143 struct cfdriver fd_cd = {
144 	NULL, "fd", DV_DISK
145 };
146 
147 void fdgetdisklabel __P((struct fd_softc *));
148 int fd_get_parms __P((struct fd_softc *));
149 void fdstrategy __P((struct buf *));
150 void fdstart __P((struct fd_softc *));
151 int fdintr __P((struct fdc_softc *));
152 
153 struct dkdriver fddkdriver = { fdstrategy };
154 
155 void fd_set_motor __P((struct fdc_softc *fdc, int reset));
156 void fd_motor_off __P((void *arg));
157 void fd_motor_on __P((void *arg));
158 void fdfinish __P((struct fd_softc *fd, struct buf *bp));
159 int fdformat __P((dev_t, struct fd_formb *, struct proc *));
160 __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
161 void fdretry __P((struct fd_softc *));
162 void fdtimeout __P((void *));
163 
164 int
165 fdprobe(parent, match, aux)
166 	struct device *parent;
167 	void *match, *aux;
168 {
169 	struct fdc_softc *fdc = (void *)parent;
170 	struct cfdata *cf = match;
171 	struct fdc_attach_args *fa = aux;
172 	int drive = fa->fa_drive;
173 	bus_space_tag_t iot = fdc->sc_iot;
174 	bus_space_handle_t ioh = fdc->sc_ioh;
175 	int n;
176 
177 	if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != drive)
178 		return 0;
179 	/*
180 	 * XXX
181 	 * This is to work around some odd interactions between this driver
182 	 * and SMC Ethernet cards.
183 	 */
184 	if (cf->cf_loc[0] == -1 && drive >= 2)
185 		return 0;
186 
187 	/*
188 	 * We want to keep the flags config gave us.
189 	 */
190 	fa->fa_flags = cf->cf_flags;
191 
192 	/* select drive and turn on motor */
193 	bus_space_write_1(iot, ioh, fdout, drive | FDO_FRST | FDO_MOEN(drive));
194 	/* wait for motor to spin up */
195 	delay(250000);
196 	out_fdc(iot, ioh, NE7CMD_RECAL);
197 	out_fdc(iot, ioh, drive);
198 	/* wait for recalibrate */
199 	delay(2000000);
200 	out_fdc(iot, ioh, NE7CMD_SENSEI);
201 	n = fdcresult(fdc);
202 #ifdef FD_DEBUG
203 	{
204 		int i;
205 		printf("fdprobe: status");
206 		for (i = 0; i < n; i++)
207 			printf(" %x", fdc->sc_status[i]);
208 		printf("\n");
209 	}
210 #endif
211 
212 	/* turn off motor */
213 	delay(250000);
214 	bus_space_write_1(iot, ioh, fdout, FDO_FRST);
215 
216 	/* flags & 0x20 forces the drive to be found even if it won't probe */
217 	if (!(fa->fa_flags & 0x20) && (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20))
218 		return 0;
219 
220 	return 1;
221 }
222 
223 /*
224  * Controller is working, and drive responded.  Attach it.
225  */
226 void
227 fdattach(parent, self, aux)
228 	struct device *parent, *self;
229 	void *aux;
230 {
231 	struct fdc_softc *fdc = (void *)parent;
232 	struct fd_softc *fd = (void *)self;
233 	struct fdc_attach_args *fa = aux;
234 	struct fd_type *type = fa->fa_deftype;
235 	int drive = fa->fa_drive;
236 
237 	if (!type || (fa->fa_flags & 0x10)) {
238 		/* The config has overridden this. */
239 		switch (fa->fa_flags & 0x07) {
240 		case 1:	/* 2.88MB */
241 			type = &fd_types[7];
242 			break;
243 		case 2:	/* 1.44MB */
244 			type = &fd_types[0];
245 			break;
246 		case 3: /* 1.2MB */
247 			type = &fd_types[1];
248 			break;
249 		case 4: /* 720K */
250 			type = &fd_types[4];
251 			break;
252 		case 5: /* 360K */
253 			type = &fd_types[3];
254 			break;
255 		case 6:	/* 1.2 MB japanese format */
256 			type = &fd_types[8];
257 			break;
258 #ifdef __alpha__
259 		default:
260 			/* 1.44MB, how to detect others?
261 			 * idea from NetBSD -- jay@rootaction.net
262                          */
263 			type = &fd_types[0];
264 #endif
265 		}
266 	}
267 
268 	if (type)
269 		printf(": %s %d cyl, %d head, %d sec\n", type->name,
270 		    type->tracks, type->heads, type->sectrac);
271 	else
272 		printf(": density unknown\n");
273 
274 	fd->sc_cylin = -1;
275 	fd->sc_drive = drive;
276 	fd->sc_deftype = type;
277 	fdc->sc_type[drive] = FDC_TYPE_DISK;
278 	fdc->sc_link.fdlink.sc_fd[drive] = fd;
279 
280 	/*
281 	 * Initialize and attach the disk structure.
282 	 */
283 	fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
284 	fd->sc_dk.dk_driver = &fddkdriver;
285 	disk_attach(&fd->sc_dk);
286 
287 	dk_establish(&fd->sc_dk, &fd->sc_dev);
288 	/* Needed to power off if the motor is on when we halt. */
289 	fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd);
290 
291 	/* Setup timeout structures */
292 	timeout_set(&fd->fd_motor_on_to, fd_motor_on, fd);
293 	timeout_set(&fd->fd_motor_off_to, fd_motor_off, fd);
294 	timeout_set(&fd->fdtimeout_to, fdtimeout, fd);
295 }
296 
297 /*
298  * Translate nvram type into internal data structure.  Return NULL for
299  * none/unknown/unusable.
300  */
301 struct fd_type *
302 fd_nvtotype(fdc, nvraminfo, drive)
303 	char *fdc;
304 	int nvraminfo, drive;
305 {
306 #ifdef __alpha__
307 	/* Alpha:  assume 1.44MB, idea from NetBSD sys/dev/isa/fd.c
308 	 * -- jay@rootaction.net
309 	 */
310 	return &fd_types[0]; /* 1.44MB */
311 #else
312 	int type;
313 
314 	type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0;
315 	switch (type) {
316 	case NVRAM_DISKETTE_NONE:
317 		return NULL;
318 	case NVRAM_DISKETTE_12M:
319 		return &fd_types[1];
320 	case NVRAM_DISKETTE_TYPE5:
321 	case NVRAM_DISKETTE_TYPE6:
322 		return &fd_types[7];
323 	case NVRAM_DISKETTE_144M:
324 		return &fd_types[0];
325 	case NVRAM_DISKETTE_360K:
326 		return &fd_types[3];
327 	case NVRAM_DISKETTE_720K:
328 		return &fd_types[4];
329 	default:
330 		printf("%s: drive %d: unknown device type 0x%x\n",
331 		    fdc, drive, type);
332 		return NULL;
333 	}
334 #endif
335 }
336 
337 __inline struct fd_type *
338 fd_dev_to_type(fd, dev)
339 	struct fd_softc *fd;
340 	dev_t dev;
341 {
342 	int type = FDTYPE(dev);
343 
344 	if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
345 		return NULL;
346 	return type ? &fd_types[type - 1] : fd->sc_deftype;
347 }
348 
349 void
350 fdstrategy(bp)
351 	register struct buf *bp;	/* IO operation to perform */
352 {
353 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(bp->b_dev)];
354 	int sz;
355  	int s;
356 	int fd_bsize = 128 << fd->sc_type->secsize;
357 	int bf = fd_bsize / DEV_BSIZE;
358 
359 	/* Valid unit, controller, and request? */
360 	if (bp->b_blkno < 0 ||
361 	    (((bp->b_blkno % bf) != 0 ||
362 	      (bp->b_bcount % fd_bsize) != 0) &&
363 	     (bp->b_flags & B_FORMAT) == 0)) {
364 		bp->b_error = EINVAL;
365 		goto bad;
366 	}
367 
368 	/* If it's a null transfer, return immediately. */
369 	if (bp->b_bcount == 0)
370 		goto done;
371 
372 	sz = howmany(bp->b_bcount, DEV_BSIZE);
373 
374 	if (bp->b_blkno + sz > fd->sc_type->size * bf) {
375 		sz = fd->sc_type->size * bf - bp->b_blkno;
376 		if (sz == 0)
377 			/* If exactly at end of disk, return EOF. */
378 			goto done;
379 		if (sz < 0) {
380 			/* If past end of disk, return EINVAL. */
381 			bp->b_error = EINVAL;
382 			goto bad;
383 		}
384 		/* Otherwise, truncate request. */
385 		bp->b_bcount = sz << DEV_BSHIFT;
386 	}
387 
388  	bp->b_cylin = bp->b_blkno / (fd_bsize / DEV_BSIZE) / fd->sc_type->seccyl;
389 
390 #ifdef FD_DEBUG
391 	printf("fdstrategy: b_blkno %d b_bcount %d blkno %d cylin %d sz %d\n",
392 	    bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylin, sz);
393 #endif
394 
395 	/* Queue transfer on drive, activate drive and controller if idle. */
396 	s = splbio();
397 	disksort(&fd->sc_q, bp);
398 	timeout_del(&fd->fd_motor_off_to); /* a good idea */
399 	if (!fd->sc_q.b_active)
400 		fdstart(fd);
401 #ifdef DIAGNOSTIC
402 	else {
403 		struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
404 		if (fdc->sc_state == DEVIDLE) {
405 			printf("fdstrategy: controller inactive\n");
406 			fdcstart(fdc);
407 		}
408 	}
409 #endif
410 	splx(s);
411 	return;
412 
413 bad:
414 	bp->b_flags |= B_ERROR;
415 done:
416 	/* Toss transfer; we're done early. */
417 	bp->b_resid = bp->b_bcount;
418 	biodone(bp);
419 }
420 
421 void
422 fdstart(fd)
423 	struct fd_softc *fd;
424 {
425 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
426 	int active = (fdc->sc_link.fdlink.sc_drives.tqh_first != NULL);
427 
428 	/* Link into controller queue. */
429 	fd->sc_q.b_active = 1;
430 	TAILQ_INSERT_TAIL(&fdc->sc_link.fdlink.sc_drives, fd, sc_drivechain);
431 
432 	/* If controller not already active, start it. */
433 	if (!active)
434 		fdcstart(fdc);
435 }
436 
437 void
438 fdfinish(fd, bp)
439 	struct fd_softc *fd;
440 	struct buf *bp;
441 {
442 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
443 
444 	/*
445 	 * Move this drive to the end of the queue to give others a `fair'
446 	 * chance.  We only force a switch if N operations are completed while
447 	 * another drive is waiting to be serviced, since there is a long motor
448 	 * startup delay whenever we switch.
449 	 */
450 	if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
451 		fd->sc_ops = 0;
452 		TAILQ_REMOVE(&fdc->sc_link.fdlink.sc_drives, fd, sc_drivechain);
453 		if (bp->b_actf) {
454 			TAILQ_INSERT_TAIL(&fdc->sc_link.fdlink.sc_drives, fd,
455 					  sc_drivechain);
456 		} else
457 			fd->sc_q.b_active = 0;
458 	}
459 	bp->b_resid = fd->sc_bcount;
460 	fd->sc_skip = 0;
461 	fd->sc_q.b_actf = bp->b_actf;
462 
463 	biodone(bp);
464 	/* turn off motor 5s from now */
465 	timeout_add(&fd->fd_motor_off_to, 5 * hz);
466 	fdc->sc_state = DEVIDLE;
467 }
468 
469 int
470 fdread(dev, uio, flags)
471 	dev_t dev;
472 	struct uio *uio;
473 	int flags;
474 {
475 
476 	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
477 }
478 
479 int
480 fdwrite(dev, uio, flags)
481 	dev_t dev;
482 	struct uio *uio;
483 	int flags;
484 {
485 
486 	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
487 }
488 
489 void
490 fd_set_motor(fdc, reset)
491 	struct fdc_softc *fdc;
492 	int reset;
493 {
494 	struct fd_softc *fd;
495 	u_char status;
496 	int n;
497 
498 	if ((fd = fdc->sc_link.fdlink.sc_drives.tqh_first) != NULL)
499 		status = fd->sc_drive;
500 	else
501 		status = 0;
502 	if (!reset)
503 		status |= FDO_FRST | FDO_FDMAEN;
504 	for (n = 0; n < 4; n++)
505 		if ((fd = fdc->sc_link.fdlink.sc_fd[n])
506 		    && (fd->sc_flags & FD_MOTOR))
507 			status |= FDO_MOEN(n);
508 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, status);
509 }
510 
511 void
512 fd_motor_off(arg)
513 	void *arg;
514 {
515 	struct fd_softc *fd = arg;
516 	int s;
517 
518 	s = splbio();
519 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
520 	fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0);
521 	splx(s);
522 }
523 
524 void
525 fd_motor_on(arg)
526 	void *arg;
527 {
528 	struct fd_softc *fd = arg;
529 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
530 	int s;
531 
532 	s = splbio();
533 	fd->sc_flags &= ~FD_MOTOR_WAIT;
534 	if ((fdc->sc_link.fdlink.sc_drives.tqh_first == fd)
535 	    && (fdc->sc_state == MOTORWAIT))
536 		(void) fdintr(fdc);
537 	splx(s);
538 }
539 
540 int
541 fdopen(dev, flags, mode, p)
542 	dev_t dev;
543 	int flags;
544 	int mode;
545 	struct proc *p;
546 {
547  	int unit;
548 	struct fd_softc *fd;
549 	struct fd_type *type;
550 
551 	unit = FDUNIT(dev);
552 	if (unit >= fd_cd.cd_ndevs)
553 		return ENXIO;
554 	fd = fd_cd.cd_devs[unit];
555 	if (fd == 0)
556 		return ENXIO;
557 	type = fd_dev_to_type(fd, dev);
558 	if (type == NULL)
559 		return ENXIO;
560 
561 	if ((fd->sc_flags & FD_OPEN) != 0 &&
562 	    fd->sc_type != type)
563 		return EBUSY;
564 
565 	fd->sc_type = type;
566 	fd->sc_cylin = -1;
567 	fd->sc_flags |= FD_OPEN;
568 
569 	return 0;
570 }
571 
572 int
573 fdclose(dev, flags, mode, p)
574 	dev_t dev;
575 	int flags;
576 	int mode;
577 	struct proc *p;
578 {
579 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
580 
581 	fd->sc_flags &= ~FD_OPEN;
582 	fd->sc_opts &= ~FDOPT_NORETRY;
583 	return 0;
584 }
585 
586 int
587 fdsize(dev)
588 	dev_t dev;
589 {
590 
591 	/* Swapping to floppies would not make sense. */
592 	return -1;
593 }
594 
595 int
596 fddump(dev, blkno, va, size)
597 	dev_t dev;
598 	daddr_t blkno;
599 	caddr_t va;
600 	size_t size;
601 {
602 
603 	/* Not implemented. */
604 	return ENXIO;
605 }
606 
607 /*
608  * Called from the controller.
609  */
610 int
611 fdintr(fdc)
612 	struct fdc_softc *fdc;
613 {
614 #define	st0	fdc->sc_status[0]
615 #define	cyl	fdc->sc_status[1]
616 	struct fd_softc *fd;
617 	struct buf *bp;
618 	bus_space_tag_t iot = fdc->sc_iot;
619 	bus_space_handle_t ioh = fdc->sc_ioh;
620 	bus_space_handle_t ioh_ctl = fdc->sc_ioh_ctl;
621 	int read, head, sec, i, nblks;
622 	struct fd_type *type;
623 	struct fd_formb *finfo = NULL;
624 	int fd_bsize, bf;
625 
626 loop:
627 	/* Is there a transfer to this drive?  If not, deactivate drive. */
628 	fd = fdc->sc_link.fdlink.sc_drives.tqh_first;
629 	if (fd == NULL) {
630 		fdc->sc_state = DEVIDLE;
631 		return 1;
632 	}
633 	fd_bsize = 128 << fd->sc_type->secsize;
634 	bf = fd_bsize / FDC_BSIZE;
635 
636 	bp = fd->sc_q.b_actf;
637 	if (bp == NULL) {
638 		fd->sc_ops = 0;
639 		TAILQ_REMOVE(&fdc->sc_link.fdlink.sc_drives, fd, sc_drivechain);
640 		fd->sc_q.b_active = 0;
641 		goto loop;
642 	}
643 
644 	if (bp->b_flags & B_FORMAT)
645 	    finfo = (struct fd_formb *)bp->b_data;
646 
647 	switch (fdc->sc_state) {
648 	case DEVIDLE:
649 		fdc->sc_errors = 0;
650 		fd->sc_skip = 0;
651 		fd->sc_bcount = bp->b_bcount;
652 		fd->sc_blkno = bp->b_blkno / (fd_bsize / DEV_BSIZE);
653 		timeout_del(&fd->fd_motor_off_to);
654 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
655 			fdc->sc_state = MOTORWAIT;
656 			return 1;
657 		}
658 		if ((fd->sc_flags & FD_MOTOR) == 0) {
659 			/* Turn on the motor, being careful about pairing. */
660 			struct fd_softc *ofd =
661 				fdc->sc_link.fdlink.sc_fd[fd->sc_drive ^ 1];
662 			if (ofd && ofd->sc_flags & FD_MOTOR) {
663 				timeout_del(&ofd->fd_motor_off_to);
664 				ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
665 			}
666 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
667 			fd_set_motor(fdc, 0);
668 			fdc->sc_state = MOTORWAIT;
669 			/* Allow .25s for motor to stabilize. */
670 			timeout_add(&fd->fd_motor_on_to, hz / 4);
671 			return 1;
672 		}
673 		/* Make sure the right drive is selected. */
674 		fd_set_motor(fdc, 0);
675 
676 		/* fall through */
677 	case DOSEEK:
678 	doseek:
679 		if (fd->sc_cylin == bp->b_cylin)
680 			goto doio;
681 
682 		out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
683 		out_fdc(iot, ioh, fd->sc_type->steprate);
684 		out_fdc(iot, ioh, 6);		/* XXX head load time == 6ms */
685 
686 		out_fdc(iot, ioh, NE7CMD_SEEK);	/* seek function */
687 		out_fdc(iot, ioh, fd->sc_drive);	/* drive number */
688 		out_fdc(iot, ioh, bp->b_cylin * fd->sc_type->step);
689 
690 		fd->sc_cylin = -1;
691 		fdc->sc_state = SEEKWAIT;
692 
693 		fd->sc_dk.dk_seek++;
694 		disk_busy(&fd->sc_dk);
695 
696 		timeout_add(&fd->fdtimeout_to, 4 * hz);
697 		return 1;
698 
699 	case DOIO:
700 	doio:
701 		type = fd->sc_type;
702 		if (finfo)
703 		    fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
704 			(char *)finfo;
705 		sec = fd->sc_blkno % type->seccyl;
706 		nblks = type->seccyl - sec;
707 		nblks = min(nblks, fd->sc_bcount / fd_bsize);
708 		nblks = min(nblks, FDC_MAXIOSIZE / fd_bsize);
709 		fd->sc_nblks = nblks;
710 		fd->sc_nbytes = finfo ? bp->b_bcount : nblks * fd_bsize;
711 		head = sec / type->sectrac;
712 		sec -= head * type->sectrac;
713 #ifdef DIAGNOSTIC
714 		{int block;
715 		 block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec;
716 		 if (block != fd->sc_blkno) {
717 			 printf("fdintr: block %d != blkno %d\n", block, fd->sc_blkno);
718 #ifdef DDB
719 			 Debugger();
720 #endif
721 		 }}
722 #endif
723 		read = bp->b_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE;
724 		isadma_start(bp->b_data + fd->sc_skip, fd->sc_nbytes,
725 		    fdc->sc_drq, read);
726 		bus_space_write_1(iot, ioh_ctl, fdctl, type->rate);
727 #ifdef FD_DEBUG
728 		printf("fdintr: %s drive %d track %d head %d sec %d nblks %d\n",
729 		    read ? "read" : "write", fd->sc_drive, fd->sc_cylin, head,
730 		    sec, nblks);
731 #endif
732 		if (finfo) {
733                         /* formatting */
734 			if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) {
735 			    fdc->sc_errors = 4;
736 			    fdretry(fd);
737 			    goto loop;
738 			}
739                         out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
740                         out_fdc(iot, ioh, finfo->fd_formb_secshift);
741                         out_fdc(iot, ioh, finfo->fd_formb_nsecs);
742                         out_fdc(iot, ioh, finfo->fd_formb_gaplen);
743                         out_fdc(iot, ioh, finfo->fd_formb_fillbyte);
744 		} else {
745 			if (read)
746 				out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
747 			else
748 				out_fdc(iot, ioh, NE7CMD_WRITE);/* WRITE */
749 			out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
750 			out_fdc(iot, ioh, fd->sc_cylin);	/* track */
751 			out_fdc(iot, ioh, head);
752 			out_fdc(iot, ioh, sec + 1);		/* sec +1 */
753 			out_fdc(iot, ioh, type->secsize);	/* sec size */
754 			out_fdc(iot, ioh, type->sectrac);	/* secs/track */
755 			out_fdc(iot, ioh, type->gap1);		/* gap1 size */
756 			out_fdc(iot, ioh, type->datalen);	/* data len */
757 		}
758 		fdc->sc_state = IOCOMPLETE;
759 
760 		disk_busy(&fd->sc_dk);
761 
762 		/* allow 2 seconds for operation */
763 		timeout_add(&fd->fdtimeout_to, 2 * hz);
764 		return 1;				/* will return later */
765 
766 	case SEEKWAIT:
767 		timeout_del(&fd->fdtimeout_to);
768 		fdc->sc_state = SEEKCOMPLETE;
769 		/* allow 1/50 second for heads to settle */
770 		timeout_add(&fdc->fdcpseudointr_to, hz / 50);
771 		return 1;
772 
773 	case SEEKCOMPLETE:
774 		disk_unbusy(&fd->sc_dk, 0);	/* no data on seek */
775 
776 		/* Make sure seek really happened. */
777 		out_fdc(iot, ioh, NE7CMD_SENSEI);
778 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
779 		    cyl != bp->b_cylin * fd->sc_type->step) {
780 #ifdef FD_DEBUG
781 			fdcstatus(&fd->sc_dev, 2, "seek failed");
782 #endif
783 			fdretry(fd);
784 			goto loop;
785 		}
786 		fd->sc_cylin = bp->b_cylin;
787 		goto doio;
788 
789 	case IOTIMEDOUT:
790 		isadma_abort(fdc->sc_drq);
791 	case SEEKTIMEDOUT:
792 	case RECALTIMEDOUT:
793 	case RESETTIMEDOUT:
794 		fdretry(fd);
795 		goto loop;
796 
797 	case IOCOMPLETE: /* IO DONE, post-analyze */
798 		timeout_del(&fd->fdtimeout_to);
799 
800 		disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid));
801 
802 		if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) {
803 			isadma_abort(fdc->sc_drq);
804 #ifdef FD_DEBUG
805 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
806 			    "read failed" : "write failed");
807 			printf("blkno %d nblks %d\n",
808 			    fd->sc_blkno, fd->sc_nblks);
809 #endif
810 			fdretry(fd);
811 			goto loop;
812 		}
813 		read = bp->b_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE;
814 		isadma_done(fdc->sc_drq);
815 		if (fdc->sc_errors) {
816 			diskerr(bp, "fd", "soft error", LOG_PRINTF,
817 			    fd->sc_skip / fd_bsize, (struct disklabel *)NULL);
818 			printf("\n");
819 			fdc->sc_errors = 0;
820 		}
821 		fd->sc_blkno += fd->sc_nblks;
822 		fd->sc_skip += fd->sc_nbytes;
823 		fd->sc_bcount -= fd->sc_nbytes;
824 		if (!finfo && fd->sc_bcount > 0) {
825 			bp->b_cylin = fd->sc_blkno / fd->sc_type->seccyl;
826 			goto doseek;
827 		}
828 		fdfinish(fd, bp);
829 		goto loop;
830 
831 	case DORESET:
832 		/* try a reset, keep motor on */
833 		fd_set_motor(fdc, 1);
834 		delay(100);
835 		fd_set_motor(fdc, 0);
836 		fdc->sc_state = RESETCOMPLETE;
837 		timeout_add(&fd->fdtimeout_to, hz / 2);
838 		return 1;			/* will return later */
839 
840 	case RESETCOMPLETE:
841 		timeout_del(&fd->fdtimeout_to);
842 		/* clear the controller output buffer */
843 		for (i = 0; i < 4; i++) {
844 			out_fdc(iot, ioh, NE7CMD_SENSEI);
845 			(void) fdcresult(fdc);
846 		}
847 
848 		/* fall through */
849 	case DORECAL:
850 		out_fdc(iot, ioh, NE7CMD_RECAL);	/* recal function */
851 		out_fdc(iot, ioh, fd->sc_drive);
852 		fdc->sc_state = RECALWAIT;
853 		timeout_add(&fd->fdtimeout_to, 5 * hz);
854 		return 1;			/* will return later */
855 
856 	case RECALWAIT:
857 		timeout_del(&fd->fdtimeout_to);
858 		fdc->sc_state = RECALCOMPLETE;
859 		/* allow 1/30 second for heads to settle */
860 		timeout_add(&fdc->fdcpseudointr_to, hz / 30);
861 		return 1;			/* will return later */
862 
863 	case RECALCOMPLETE:
864 		out_fdc(iot, ioh, NE7CMD_SENSEI);
865 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
866 #ifdef FD_DEBUG
867 			fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
868 #endif
869 			fdretry(fd);
870 			goto loop;
871 		}
872 		fd->sc_cylin = 0;
873 		goto doseek;
874 
875 	case MOTORWAIT:
876 		if (fd->sc_flags & FD_MOTOR_WAIT)
877 			return 1;		/* time's not up yet */
878 		goto doseek;
879 
880 	default:
881 		fdcstatus(&fd->sc_dev, 0, "stray interrupt");
882 		return 1;
883 	}
884 #ifdef DIAGNOSTIC
885 	panic("fdintr: impossible");
886 #endif
887 #undef	st0
888 #undef	cyl
889 }
890 
891 void
892 fdtimeout(arg)
893 	void *arg;
894 {
895 	struct fd_softc *fd = arg;
896 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
897 	int s;
898 
899 	s = splbio();
900 #ifdef DEBUG
901 	log(LOG_ERR,"fdtimeout: state %d\n", fdc->sc_state);
902 #endif
903 	fdcstatus(&fd->sc_dev, 0, "timeout");
904 
905 	if (fd->sc_q.b_actf)
906 		fdc->sc_state++;
907 	else
908 		fdc->sc_state = DEVIDLE;
909 
910 	(void) fdintr(fdc);
911 	splx(s);
912 }
913 
914 void
915 fdretry(fd)
916 	struct fd_softc *fd;
917 {
918 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
919 	struct buf *bp = fd->sc_q.b_actf;
920 
921 	if (fd->sc_opts & FDOPT_NORETRY)
922 	    goto fail;
923 	switch (fdc->sc_errors) {
924 	case 0:
925 		/* try again */
926 		fdc->sc_state = DOSEEK;
927 		break;
928 
929 	case 1: case 2: case 3:
930 		/* didn't work; try recalibrating */
931 		fdc->sc_state = DORECAL;
932 		break;
933 
934 	case 4:
935 		/* still no go; reset the bastard */
936 		fdc->sc_state = DORESET;
937 		break;
938 
939 	default:
940 	fail:
941 		diskerr(bp, "fd", "hard error", LOG_PRINTF,
942 		    fd->sc_skip / (128 << fd->sc_type->secsize),
943 		    (struct disklabel *)NULL);
944 		printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n",
945 		    fdc->sc_status[0], NE7_ST0BITS,
946 		    fdc->sc_status[1], NE7_ST1BITS,
947 		    fdc->sc_status[2], NE7_ST2BITS,
948 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
949 
950 		bp->b_flags |= B_ERROR;
951 		bp->b_error = EIO;
952 		fdfinish(fd, bp);
953 	}
954 	fdc->sc_errors++;
955 }
956 
957 int
958 fdioctl(dev, cmd, addr, flag, p)
959 	dev_t dev;
960 	u_long cmd;
961 	caddr_t addr;
962 	int flag;
963 	struct proc *p;
964 {
965 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
966 	struct disklabel dl, *lp = &dl;
967 	struct cpu_disklabel cdl;
968 	char *errstring;
969 	int error;
970 
971 	switch (cmd) {
972 	case MTIOCTOP:
973 		if (((struct mtop *)addr)->mt_op != MTOFFL)
974 			return EIO;
975 		return (0);
976 	case DIOCGDINFO:
977 		bzero(lp, sizeof(*lp));
978 		bzero(&cdl, sizeof(struct cpu_disklabel));
979 
980 		lp->d_secsize = 128 << fd->sc_type->secsize;
981 		lp->d_secpercyl = fd->sc_type->seccyl;
982 		lp->d_ntracks = fd->sc_type->heads;
983 		lp->d_nsectors = fd->sc_type->sectrac;
984 		lp->d_ncylinders = fd->sc_type->tracks;
985 
986 		strncpy(lp->d_typename, "floppy disk", 16);
987 		lp->d_type = DTYPE_FLOPPY;
988 		strncpy(lp->d_packname, "fictitious", 16);
989 		lp->d_secperunit = fd->sc_type->size;
990 		lp->d_rpm = 300;
991 		lp->d_interleave = 1;
992 		lp->d_flags = D_REMOVABLE;
993 
994 		lp->d_partitions[RAW_PART].p_offset = 0;
995 		lp->d_partitions[RAW_PART].p_size =
996 		    lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
997 		lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
998 		lp->d_npartitions = RAW_PART + 1;
999 
1000 		lp->d_magic = DISKMAGIC;
1001 		lp->d_magic2 = DISKMAGIC;
1002 		lp->d_checksum = dkcksum(lp);
1003 
1004 		errstring = readdisklabel(dev, fdstrategy, lp, &cdl, 0);
1005 		if (errstring) {
1006 			/*printf("%s: %s\n", fd->sc_dev.dv_xname, errstring); */
1007 		}
1008 
1009 		*(struct disklabel *)addr = *lp;
1010 		return 0;
1011 
1012 	case DIOCWLABEL:
1013 		if ((flag & FWRITE) == 0)
1014 			return EBADF;
1015 		/* XXX do something */
1016 		return 0;
1017 
1018 	case DIOCWDINFO:
1019 		if ((flag & FWRITE) == 0)
1020 			return EBADF;
1021 
1022 		error = setdisklabel(lp, (struct disklabel *)addr, 0, NULL);
1023 		if (error)
1024 			return error;
1025 
1026 		error = writedisklabel(dev, fdstrategy, lp, NULL);
1027 		return error;
1028 
1029         case FD_FORM:
1030                 if((flag & FWRITE) == 0)
1031                         return EBADF;  /* must be opened for writing */
1032                 else if(((struct fd_formb *)addr)->format_version !=
1033                         FD_FORMAT_VERSION)
1034                         return EINVAL; /* wrong version of formatting prog */
1035                 else
1036                         return fdformat(dev, (struct fd_formb *)addr, p);
1037                 break;
1038 
1039         case FD_GTYPE:                  /* get drive type */
1040                 *(struct fd_type *)addr = *fd->sc_type;
1041 		return 0;
1042 
1043         case FD_GOPTS:                  /* get drive options */
1044                 *(int *)addr = fd->sc_opts;
1045                 return 0;
1046 
1047         case FD_SOPTS:                  /* set drive options */
1048                 fd->sc_opts = *(int *)addr;
1049 		return 0;
1050 
1051 	default:
1052 		return ENOTTY;
1053 	}
1054 
1055 #ifdef DIAGNOSTIC
1056 	panic("fdioctl: impossible");
1057 #endif
1058 }
1059 
1060 int
1061 fdformat(dev, finfo, p)
1062         dev_t dev;
1063         struct fd_formb *finfo;
1064         struct proc *p;
1065 {
1066         int rv = 0, s;
1067 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1068 	struct fd_type *type = fd->sc_type;
1069         struct buf *bp;
1070 	int fd_bsize = 128 << fd->sc_type->secsize;
1071 
1072         /* set up a buffer header for fdstrategy() */
1073         bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
1074         if(bp == 0)
1075                 return ENOBUFS;
1076         bzero((void *)bp, sizeof(struct buf));
1077         bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
1078         bp->b_proc = p;
1079         bp->b_dev = dev;
1080 
1081         /*
1082          * calculate a fake blkno, so fdstrategy() would initiate a
1083          * seek to the requested cylinder
1084          */
1085         bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
1086                 + finfo->head * type->sectrac) * fd_bsize / DEV_BSIZE;
1087 
1088         bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1089         bp->b_data = (caddr_t)finfo;
1090 
1091 #ifdef DEBUG
1092 	printf("fdformat: blkno %x count %x\n", bp->b_blkno, bp->b_bcount);
1093 #endif
1094 
1095         /* now do the format */
1096         fdstrategy(bp);
1097 
1098         /* ...and wait for it to complete */
1099         s = splbio();
1100         while(!(bp->b_flags & B_DONE))
1101         {
1102                 rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 0);
1103                 if(rv == EWOULDBLOCK)
1104 		    /*break*/;
1105         }
1106         splx(s);
1107 
1108         if(rv == EWOULDBLOCK) {
1109                 /* timed out */
1110                 rv = EIO;
1111 		/* XXX what to do to the buf? it will eventually fall
1112 		   out as finished, but ... ?*/
1113 		/*biodone(bp);*/
1114 	}
1115         if(bp->b_flags & B_ERROR)
1116                 rv = bp->b_error;
1117         free(bp, M_TEMP);
1118         return rv;
1119 }
1120