xref: /openbsd-src/sys/dev/isa/fd.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: fd.c,v 1.42 2001/03/06 13:55:02 ho 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 		}
259 	}
260 
261 	if (type)
262 		printf(": %s %d cyl, %d head, %d sec\n", type->name,
263 		    type->tracks, type->heads, type->sectrac);
264 	else
265 		printf(": density unknown\n");
266 
267 	fd->sc_cylin = -1;
268 	fd->sc_drive = drive;
269 	fd->sc_deftype = type;
270 	fdc->sc_type[drive] = FDC_TYPE_DISK;
271 	fdc->sc_link.fdlink.sc_fd[drive] = fd;
272 
273 	/*
274 	 * Initialize and attach the disk structure.
275 	 */
276 	fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
277 	fd->sc_dk.dk_driver = &fddkdriver;
278 	disk_attach(&fd->sc_dk);
279 
280 	dk_establish(&fd->sc_dk, &fd->sc_dev);
281 	/* Needed to power off if the motor is on when we halt. */
282 	fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd);
283 
284 	/* Setup timeout structures */
285 	timeout_set(&fd->fd_motor_on_to, fd_motor_on, fd);
286 	timeout_set(&fd->fd_motor_off_to, fd_motor_off, fd);
287 	timeout_set(&fd->fdtimeout_to, fdtimeout, fd);
288 }
289 
290 /*
291  * Translate nvram type into internal data structure.  Return NULL for
292  * none/unknown/unusable.
293  */
294 struct fd_type *
295 fd_nvtotype(fdc, nvraminfo, drive)
296 	char *fdc;
297 	int nvraminfo, drive;
298 {
299 	int type;
300 
301 	type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0;
302 	switch (type) {
303 	case NVRAM_DISKETTE_NONE:
304 		return NULL;
305 	case NVRAM_DISKETTE_12M:
306 		return &fd_types[1];
307 	case NVRAM_DISKETTE_TYPE5:
308 	case NVRAM_DISKETTE_TYPE6:
309 		return &fd_types[7];
310 	case NVRAM_DISKETTE_144M:
311 		return &fd_types[0];
312 	case NVRAM_DISKETTE_360K:
313 		return &fd_types[3];
314 	case NVRAM_DISKETTE_720K:
315 		return &fd_types[4];
316 	default:
317 		printf("%s: drive %d: unknown device type 0x%x\n",
318 		    fdc, drive, type);
319 		return NULL;
320 	}
321 }
322 
323 __inline struct fd_type *
324 fd_dev_to_type(fd, dev)
325 	struct fd_softc *fd;
326 	dev_t dev;
327 {
328 	int type = FDTYPE(dev);
329 
330 	if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
331 		return NULL;
332 	return type ? &fd_types[type - 1] : fd->sc_deftype;
333 }
334 
335 void
336 fdstrategy(bp)
337 	register struct buf *bp;	/* IO operation to perform */
338 {
339 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(bp->b_dev)];
340 	int sz;
341  	int s;
342 	int fd_bsize = 128 << fd->sc_type->secsize;
343 	int bf = fd_bsize / DEV_BSIZE;
344 
345 	/* Valid unit, controller, and request? */
346 	if (bp->b_blkno < 0 ||
347 	    (((bp->b_blkno % bf) != 0 ||
348 	      (bp->b_bcount % fd_bsize) != 0) &&
349 	     (bp->b_flags & B_FORMAT) == 0)) {
350 		bp->b_error = EINVAL;
351 		goto bad;
352 	}
353 
354 	/* If it's a null transfer, return immediately. */
355 	if (bp->b_bcount == 0)
356 		goto done;
357 
358 	sz = howmany(bp->b_bcount, DEV_BSIZE);
359 
360 	if (bp->b_blkno + sz > fd->sc_type->size * bf) {
361 		sz = fd->sc_type->size * bf - bp->b_blkno;
362 		if (sz == 0)
363 			/* If exactly at end of disk, return EOF. */
364 			goto done;
365 		if (sz < 0) {
366 			/* If past end of disk, return EINVAL. */
367 			bp->b_error = EINVAL;
368 			goto bad;
369 		}
370 		/* Otherwise, truncate request. */
371 		bp->b_bcount = sz << DEV_BSHIFT;
372 	}
373 
374  	bp->b_cylin = bp->b_blkno / (fd_bsize / DEV_BSIZE) / fd->sc_type->seccyl;
375 
376 #ifdef FD_DEBUG
377 	printf("fdstrategy: b_blkno %d b_bcount %d blkno %d cylin %d sz %d\n",
378 	    bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylin, sz);
379 #endif
380 
381 	/* Queue transfer on drive, activate drive and controller if idle. */
382 	s = splbio();
383 	disksort(&fd->sc_q, bp);
384 	timeout_del(&fd->fd_motor_off_to); /* a good idea */
385 	if (!fd->sc_q.b_active)
386 		fdstart(fd);
387 #ifdef DIAGNOSTIC
388 	else {
389 		struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
390 		if (fdc->sc_state == DEVIDLE) {
391 			printf("fdstrategy: controller inactive\n");
392 			fdcstart(fdc);
393 		}
394 	}
395 #endif
396 	splx(s);
397 	return;
398 
399 bad:
400 	bp->b_flags |= B_ERROR;
401 done:
402 	/* Toss transfer; we're done early. */
403 	bp->b_resid = bp->b_bcount;
404 	biodone(bp);
405 }
406 
407 void
408 fdstart(fd)
409 	struct fd_softc *fd;
410 {
411 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
412 	int active = (fdc->sc_link.fdlink.sc_drives.tqh_first != NULL);
413 
414 	/* Link into controller queue. */
415 	fd->sc_q.b_active = 1;
416 	TAILQ_INSERT_TAIL(&fdc->sc_link.fdlink.sc_drives, fd, sc_drivechain);
417 
418 	/* If controller not already active, start it. */
419 	if (!active)
420 		fdcstart(fdc);
421 }
422 
423 void
424 fdfinish(fd, bp)
425 	struct fd_softc *fd;
426 	struct buf *bp;
427 {
428 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
429 
430 	/*
431 	 * Move this drive to the end of the queue to give others a `fair'
432 	 * chance.  We only force a switch if N operations are completed while
433 	 * another drive is waiting to be serviced, since there is a long motor
434 	 * startup delay whenever we switch.
435 	 */
436 	if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
437 		fd->sc_ops = 0;
438 		TAILQ_REMOVE(&fdc->sc_link.fdlink.sc_drives, fd, sc_drivechain);
439 		if (bp->b_actf) {
440 			TAILQ_INSERT_TAIL(&fdc->sc_link.fdlink.sc_drives, fd,
441 					  sc_drivechain);
442 		} else
443 			fd->sc_q.b_active = 0;
444 	}
445 	bp->b_resid = fd->sc_bcount;
446 	fd->sc_skip = 0;
447 	fd->sc_q.b_actf = bp->b_actf;
448 
449 	biodone(bp);
450 	/* turn off motor 5s from now */
451 	timeout_add(&fd->fd_motor_off_to, 5 * hz);
452 	fdc->sc_state = DEVIDLE;
453 }
454 
455 int
456 fdread(dev, uio, flags)
457 	dev_t dev;
458 	struct uio *uio;
459 	int flags;
460 {
461 
462 	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
463 }
464 
465 int
466 fdwrite(dev, uio, flags)
467 	dev_t dev;
468 	struct uio *uio;
469 	int flags;
470 {
471 
472 	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
473 }
474 
475 void
476 fd_set_motor(fdc, reset)
477 	struct fdc_softc *fdc;
478 	int reset;
479 {
480 	struct fd_softc *fd;
481 	u_char status;
482 	int n;
483 
484 	if ((fd = fdc->sc_link.fdlink.sc_drives.tqh_first) != NULL)
485 		status = fd->sc_drive;
486 	else
487 		status = 0;
488 	if (!reset)
489 		status |= FDO_FRST | FDO_FDMAEN;
490 	for (n = 0; n < 4; n++)
491 		if ((fd = fdc->sc_link.fdlink.sc_fd[n])
492 		    && (fd->sc_flags & FD_MOTOR))
493 			status |= FDO_MOEN(n);
494 	bus_space_write_1(fdc->sc_iot, fdc->sc_ioh, fdout, status);
495 }
496 
497 void
498 fd_motor_off(arg)
499 	void *arg;
500 {
501 	struct fd_softc *fd = arg;
502 	int s;
503 
504 	s = splbio();
505 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
506 	fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0);
507 	splx(s);
508 }
509 
510 void
511 fd_motor_on(arg)
512 	void *arg;
513 {
514 	struct fd_softc *fd = arg;
515 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
516 	int s;
517 
518 	s = splbio();
519 	fd->sc_flags &= ~FD_MOTOR_WAIT;
520 	if ((fdc->sc_link.fdlink.sc_drives.tqh_first == fd)
521 	    && (fdc->sc_state == MOTORWAIT))
522 		(void) fdintr(fdc);
523 	splx(s);
524 }
525 
526 int
527 fdopen(dev, flags, mode, p)
528 	dev_t dev;
529 	int flags;
530 	int mode;
531 	struct proc *p;
532 {
533  	int unit;
534 	struct fd_softc *fd;
535 	struct fd_type *type;
536 
537 	unit = FDUNIT(dev);
538 	if (unit >= fd_cd.cd_ndevs)
539 		return ENXIO;
540 	fd = fd_cd.cd_devs[unit];
541 	if (fd == 0)
542 		return ENXIO;
543 	type = fd_dev_to_type(fd, dev);
544 	if (type == NULL)
545 		return ENXIO;
546 
547 	if ((fd->sc_flags & FD_OPEN) != 0 &&
548 	    fd->sc_type != type)
549 		return EBUSY;
550 
551 	fd->sc_type = type;
552 	fd->sc_cylin = -1;
553 	fd->sc_flags |= FD_OPEN;
554 
555 	return 0;
556 }
557 
558 int
559 fdclose(dev, flags, mode, p)
560 	dev_t dev;
561 	int flags;
562 	int mode;
563 	struct proc *p;
564 {
565 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
566 
567 	fd->sc_flags &= ~FD_OPEN;
568 	fd->sc_opts &= ~FDOPT_NORETRY;
569 	return 0;
570 }
571 
572 int
573 fdsize(dev)
574 	dev_t dev;
575 {
576 
577 	/* Swapping to floppies would not make sense. */
578 	return -1;
579 }
580 
581 int
582 fddump(dev, blkno, va, size)
583 	dev_t dev;
584 	daddr_t blkno;
585 	caddr_t va;
586 	size_t size;
587 {
588 
589 	/* Not implemented. */
590 	return ENXIO;
591 }
592 
593 /*
594  * Called from the controller.
595  */
596 int
597 fdintr(fdc)
598 	struct fdc_softc *fdc;
599 {
600 #define	st0	fdc->sc_status[0]
601 #define	cyl	fdc->sc_status[1]
602 	struct fd_softc *fd;
603 	struct buf *bp;
604 	bus_space_tag_t iot = fdc->sc_iot;
605 	bus_space_handle_t ioh = fdc->sc_ioh;
606 	bus_space_handle_t ioh_ctl = fdc->sc_ioh_ctl;
607 	int read, head, sec, i, nblks;
608 	struct fd_type *type;
609 	struct fd_formb *finfo = NULL;
610 	int fd_bsize, bf;
611 
612 loop:
613 	/* Is there a transfer to this drive?  If not, deactivate drive. */
614 	fd = fdc->sc_link.fdlink.sc_drives.tqh_first;
615 	if (fd == NULL) {
616 		fdc->sc_state = DEVIDLE;
617 		return 1;
618 	}
619 	fd_bsize = 128 << fd->sc_type->secsize;
620 	bf = fd_bsize / FDC_BSIZE;
621 
622 	bp = fd->sc_q.b_actf;
623 	if (bp == NULL) {
624 		fd->sc_ops = 0;
625 		TAILQ_REMOVE(&fdc->sc_link.fdlink.sc_drives, fd, sc_drivechain);
626 		fd->sc_q.b_active = 0;
627 		goto loop;
628 	}
629 
630 	if (bp->b_flags & B_FORMAT)
631 	    finfo = (struct fd_formb *)bp->b_data;
632 
633 	switch (fdc->sc_state) {
634 	case DEVIDLE:
635 		fdc->sc_errors = 0;
636 		fd->sc_skip = 0;
637 		fd->sc_bcount = bp->b_bcount;
638 		fd->sc_blkno = bp->b_blkno / (fd_bsize / DEV_BSIZE);
639 		timeout_del(&fd->fd_motor_off_to);
640 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
641 			fdc->sc_state = MOTORWAIT;
642 			return 1;
643 		}
644 		if ((fd->sc_flags & FD_MOTOR) == 0) {
645 			/* Turn on the motor, being careful about pairing. */
646 			struct fd_softc *ofd =
647 				fdc->sc_link.fdlink.sc_fd[fd->sc_drive ^ 1];
648 			if (ofd && ofd->sc_flags & FD_MOTOR) {
649 				timeout_del(&ofd->fd_motor_off_to);
650 				ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
651 			}
652 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
653 			fd_set_motor(fdc, 0);
654 			fdc->sc_state = MOTORWAIT;
655 			/* Allow .25s for motor to stabilize. */
656 			timeout_add(&fd->fd_motor_on_to, hz / 4);
657 			return 1;
658 		}
659 		/* Make sure the right drive is selected. */
660 		fd_set_motor(fdc, 0);
661 
662 		/* fall through */
663 	case DOSEEK:
664 	doseek:
665 		if (fd->sc_cylin == bp->b_cylin)
666 			goto doio;
667 
668 		out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
669 		out_fdc(iot, ioh, fd->sc_type->steprate);
670 		out_fdc(iot, ioh, 6);		/* XXX head load time == 6ms */
671 
672 		out_fdc(iot, ioh, NE7CMD_SEEK);	/* seek function */
673 		out_fdc(iot, ioh, fd->sc_drive);	/* drive number */
674 		out_fdc(iot, ioh, bp->b_cylin * fd->sc_type->step);
675 
676 		fd->sc_cylin = -1;
677 		fdc->sc_state = SEEKWAIT;
678 
679 		fd->sc_dk.dk_seek++;
680 		disk_busy(&fd->sc_dk);
681 
682 		timeout_add(&fd->fdtimeout_to, 4 * hz);
683 		return 1;
684 
685 	case DOIO:
686 	doio:
687 		type = fd->sc_type;
688 		if (finfo)
689 		    fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
690 			(char *)finfo;
691 		sec = fd->sc_blkno % type->seccyl;
692 		nblks = type->seccyl - sec;
693 		nblks = min(nblks, fd->sc_bcount / fd_bsize);
694 		nblks = min(nblks, FDC_MAXIOSIZE / fd_bsize);
695 		fd->sc_nblks = nblks;
696 		fd->sc_nbytes = finfo ? bp->b_bcount : nblks * fd_bsize;
697 		head = sec / type->sectrac;
698 		sec -= head * type->sectrac;
699 #ifdef DIAGNOSTIC
700 		{int block;
701 		 block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec;
702 		 if (block != fd->sc_blkno) {
703 			 printf("fdintr: block %d != blkno %d\n", block, fd->sc_blkno);
704 #ifdef DDB
705 			 Debugger();
706 #endif
707 		 }}
708 #endif
709 		read = bp->b_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE;
710 		isadma_start(bp->b_data + fd->sc_skip, fd->sc_nbytes,
711 		    fdc->sc_drq, read);
712 		bus_space_write_1(iot, ioh_ctl, fdctl, type->rate);
713 #ifdef FD_DEBUG
714 		printf("fdintr: %s drive %d track %d head %d sec %d nblks %d\n",
715 		    read ? "read" : "write", fd->sc_drive, fd->sc_cylin, head,
716 		    sec, nblks);
717 #endif
718 		if (finfo) {
719                         /* formatting */
720 			if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) {
721 			    fdc->sc_errors = 4;
722 			    fdretry(fd);
723 			    goto loop;
724 			}
725                         out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
726                         out_fdc(iot, ioh, finfo->fd_formb_secshift);
727                         out_fdc(iot, ioh, finfo->fd_formb_nsecs);
728                         out_fdc(iot, ioh, finfo->fd_formb_gaplen);
729                         out_fdc(iot, ioh, finfo->fd_formb_fillbyte);
730 		} else {
731 			if (read)
732 				out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
733 			else
734 				out_fdc(iot, ioh, NE7CMD_WRITE);/* WRITE */
735 			out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
736 			out_fdc(iot, ioh, fd->sc_cylin);	/* track */
737 			out_fdc(iot, ioh, head);
738 			out_fdc(iot, ioh, sec + 1);		/* sec +1 */
739 			out_fdc(iot, ioh, type->secsize);	/* sec size */
740 			out_fdc(iot, ioh, type->sectrac);	/* secs/track */
741 			out_fdc(iot, ioh, type->gap1);		/* gap1 size */
742 			out_fdc(iot, ioh, type->datalen);	/* data len */
743 		}
744 		fdc->sc_state = IOCOMPLETE;
745 
746 		disk_busy(&fd->sc_dk);
747 
748 		/* allow 2 seconds for operation */
749 		timeout_add(&fd->fdtimeout_to, 2 * hz);
750 		return 1;				/* will return later */
751 
752 	case SEEKWAIT:
753 		timeout_del(&fd->fdtimeout_to);
754 		fdc->sc_state = SEEKCOMPLETE;
755 		/* allow 1/50 second for heads to settle */
756 		timeout_add(&fdc->fdcpseudointr_to, hz / 50);
757 		return 1;
758 
759 	case SEEKCOMPLETE:
760 		disk_unbusy(&fd->sc_dk, 0);	/* no data on seek */
761 
762 		/* Make sure seek really happened. */
763 		out_fdc(iot, ioh, NE7CMD_SENSEI);
764 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
765 		    cyl != bp->b_cylin * fd->sc_type->step) {
766 #ifdef FD_DEBUG
767 			fdcstatus(&fd->sc_dev, 2, "seek failed");
768 #endif
769 			fdretry(fd);
770 			goto loop;
771 		}
772 		fd->sc_cylin = bp->b_cylin;
773 		goto doio;
774 
775 	case IOTIMEDOUT:
776 		isadma_abort(fdc->sc_drq);
777 	case SEEKTIMEDOUT:
778 	case RECALTIMEDOUT:
779 	case RESETTIMEDOUT:
780 		fdretry(fd);
781 		goto loop;
782 
783 	case IOCOMPLETE: /* IO DONE, post-analyze */
784 		timeout_del(&fd->fdtimeout_to);
785 
786 		disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid));
787 
788 		if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) {
789 			isadma_abort(fdc->sc_drq);
790 #ifdef FD_DEBUG
791 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
792 			    "read failed" : "write failed");
793 			printf("blkno %d nblks %d\n",
794 			    fd->sc_blkno, fd->sc_nblks);
795 #endif
796 			fdretry(fd);
797 			goto loop;
798 		}
799 		read = bp->b_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE;
800 		isadma_done(fdc->sc_drq);
801 		if (fdc->sc_errors) {
802 			diskerr(bp, "fd", "soft error", LOG_PRINTF,
803 			    fd->sc_skip / fd_bsize, (struct disklabel *)NULL);
804 			printf("\n");
805 			fdc->sc_errors = 0;
806 		}
807 		fd->sc_blkno += fd->sc_nblks;
808 		fd->sc_skip += fd->sc_nbytes;
809 		fd->sc_bcount -= fd->sc_nbytes;
810 		if (!finfo && fd->sc_bcount > 0) {
811 			bp->b_cylin = fd->sc_blkno / fd->sc_type->seccyl;
812 			goto doseek;
813 		}
814 		fdfinish(fd, bp);
815 		goto loop;
816 
817 	case DORESET:
818 		/* try a reset, keep motor on */
819 		fd_set_motor(fdc, 1);
820 		delay(100);
821 		fd_set_motor(fdc, 0);
822 		fdc->sc_state = RESETCOMPLETE;
823 		timeout_add(&fd->fdtimeout_to, hz / 2);
824 		return 1;			/* will return later */
825 
826 	case RESETCOMPLETE:
827 		timeout_del(&fd->fdtimeout_to);
828 		/* clear the controller output buffer */
829 		for (i = 0; i < 4; i++) {
830 			out_fdc(iot, ioh, NE7CMD_SENSEI);
831 			(void) fdcresult(fdc);
832 		}
833 
834 		/* fall through */
835 	case DORECAL:
836 		out_fdc(iot, ioh, NE7CMD_RECAL);	/* recal function */
837 		out_fdc(iot, ioh, fd->sc_drive);
838 		fdc->sc_state = RECALWAIT;
839 		timeout_add(&fd->fdtimeout_to, 5 * hz);
840 		return 1;			/* will return later */
841 
842 	case RECALWAIT:
843 		timeout_del(&fd->fdtimeout_to);
844 		fdc->sc_state = RECALCOMPLETE;
845 		/* allow 1/30 second for heads to settle */
846 		timeout_add(&fdc->fdcpseudointr_to, hz / 30);
847 		return 1;			/* will return later */
848 
849 	case RECALCOMPLETE:
850 		out_fdc(iot, ioh, NE7CMD_SENSEI);
851 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
852 #ifdef FD_DEBUG
853 			fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
854 #endif
855 			fdretry(fd);
856 			goto loop;
857 		}
858 		fd->sc_cylin = 0;
859 		goto doseek;
860 
861 	case MOTORWAIT:
862 		if (fd->sc_flags & FD_MOTOR_WAIT)
863 			return 1;		/* time's not up yet */
864 		goto doseek;
865 
866 	default:
867 		fdcstatus(&fd->sc_dev, 0, "stray interrupt");
868 		return 1;
869 	}
870 #ifdef DIAGNOSTIC
871 	panic("fdintr: impossible");
872 #endif
873 #undef	st0
874 #undef	cyl
875 }
876 
877 void
878 fdtimeout(arg)
879 	void *arg;
880 {
881 	struct fd_softc *fd = arg;
882 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
883 	int s;
884 
885 	s = splbio();
886 #ifdef DEBUG
887 	log(LOG_ERR,"fdtimeout: state %d\n", fdc->sc_state);
888 #endif
889 	fdcstatus(&fd->sc_dev, 0, "timeout");
890 
891 	if (fd->sc_q.b_actf)
892 		fdc->sc_state++;
893 	else
894 		fdc->sc_state = DEVIDLE;
895 
896 	(void) fdintr(fdc);
897 	splx(s);
898 }
899 
900 void
901 fdretry(fd)
902 	struct fd_softc *fd;
903 {
904 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
905 	struct buf *bp = fd->sc_q.b_actf;
906 
907 	if (fd->sc_opts & FDOPT_NORETRY)
908 	    goto fail;
909 	switch (fdc->sc_errors) {
910 	case 0:
911 		/* try again */
912 		fdc->sc_state = DOSEEK;
913 		break;
914 
915 	case 1: case 2: case 3:
916 		/* didn't work; try recalibrating */
917 		fdc->sc_state = DORECAL;
918 		break;
919 
920 	case 4:
921 		/* still no go; reset the bastard */
922 		fdc->sc_state = DORESET;
923 		break;
924 
925 	default:
926 	fail:
927 		diskerr(bp, "fd", "hard error", LOG_PRINTF,
928 		    fd->sc_skip / (128 << fd->sc_type->secsize),
929 		    (struct disklabel *)NULL);
930 		printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n",
931 		    fdc->sc_status[0], NE7_ST0BITS,
932 		    fdc->sc_status[1], NE7_ST1BITS,
933 		    fdc->sc_status[2], NE7_ST2BITS,
934 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
935 
936 		bp->b_flags |= B_ERROR;
937 		bp->b_error = EIO;
938 		fdfinish(fd, bp);
939 	}
940 	fdc->sc_errors++;
941 }
942 
943 int
944 fdioctl(dev, cmd, addr, flag, p)
945 	dev_t dev;
946 	u_long cmd;
947 	caddr_t addr;
948 	int flag;
949 	struct proc *p;
950 {
951 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
952 	struct disklabel dl, *lp = &dl;
953 	struct cpu_disklabel cdl;
954 	char *errstring;
955 	int error;
956 
957 	switch (cmd) {
958 	case MTIOCTOP:
959 		if (((struct mtop *)addr)->mt_op != MTOFFL)
960 			return EIO;
961 		return (0);
962 	case DIOCGDINFO:
963 		bzero(lp, sizeof(*lp));
964 		bzero(&cdl, sizeof(struct cpu_disklabel));
965 
966 		lp->d_secsize = 128 << fd->sc_type->secsize;
967 		lp->d_secpercyl = fd->sc_type->seccyl;
968 		lp->d_ntracks = fd->sc_type->heads;
969 		lp->d_nsectors = fd->sc_type->sectrac;
970 		lp->d_ncylinders = fd->sc_type->tracks;
971 
972 		strncpy(lp->d_typename, "floppy disk", 16);
973 		lp->d_type = DTYPE_FLOPPY;
974 		strncpy(lp->d_packname, "fictitious", 16);
975 		lp->d_secperunit = fd->sc_type->size;
976 		lp->d_rpm = 300;
977 		lp->d_interleave = 1;
978 		lp->d_flags = D_REMOVABLE;
979 
980 		lp->d_partitions[RAW_PART].p_offset = 0;
981 		lp->d_partitions[RAW_PART].p_size =
982 		    lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
983 		lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
984 		lp->d_npartitions = RAW_PART + 1;
985 
986 		lp->d_magic = DISKMAGIC;
987 		lp->d_magic2 = DISKMAGIC;
988 		lp->d_checksum = dkcksum(lp);
989 
990 		errstring = readdisklabel(dev, fdstrategy, lp, &cdl, 0);
991 		if (errstring) {
992 			/*printf("%s: %s\n", fd->sc_dev.dv_xname, errstring); */
993 		}
994 
995 		*(struct disklabel *)addr = *lp;
996 		return 0;
997 
998 	case DIOCWLABEL:
999 		if ((flag & FWRITE) == 0)
1000 			return EBADF;
1001 		/* XXX do something */
1002 		return 0;
1003 
1004 	case DIOCWDINFO:
1005 		if ((flag & FWRITE) == 0)
1006 			return EBADF;
1007 
1008 		error = setdisklabel(lp, (struct disklabel *)addr, 0, NULL);
1009 		if (error)
1010 			return error;
1011 
1012 		error = writedisklabel(dev, fdstrategy, lp, NULL);
1013 		return error;
1014 
1015         case FD_FORM:
1016                 if((flag & FWRITE) == 0)
1017                         return EBADF;  /* must be opened for writing */
1018                 else if(((struct fd_formb *)addr)->format_version !=
1019                         FD_FORMAT_VERSION)
1020                         return EINVAL; /* wrong version of formatting prog */
1021                 else
1022                         return fdformat(dev, (struct fd_formb *)addr, p);
1023                 break;
1024 
1025         case FD_GTYPE:                  /* get drive type */
1026                 *(struct fd_type *)addr = *fd->sc_type;
1027 		return 0;
1028 
1029         case FD_GOPTS:                  /* get drive options */
1030                 *(int *)addr = fd->sc_opts;
1031                 return 0;
1032 
1033         case FD_SOPTS:                  /* set drive options */
1034                 fd->sc_opts = *(int *)addr;
1035 		return 0;
1036 
1037 	default:
1038 		return ENOTTY;
1039 	}
1040 
1041 #ifdef DIAGNOSTIC
1042 	panic("fdioctl: impossible");
1043 #endif
1044 }
1045 
1046 int
1047 fdformat(dev, finfo, p)
1048         dev_t dev;
1049         struct fd_formb *finfo;
1050         struct proc *p;
1051 {
1052         int rv = 0, s;
1053 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1054 	struct fd_type *type = fd->sc_type;
1055         struct buf *bp;
1056 	int fd_bsize = 128 << fd->sc_type->secsize;
1057 
1058         /* set up a buffer header for fdstrategy() */
1059         bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
1060         if(bp == 0)
1061                 return ENOBUFS;
1062         bzero((void *)bp, sizeof(struct buf));
1063         bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
1064         bp->b_proc = p;
1065         bp->b_dev = dev;
1066 
1067         /*
1068          * calculate a fake blkno, so fdstrategy() would initiate a
1069          * seek to the requested cylinder
1070          */
1071         bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
1072                 + finfo->head * type->sectrac) * fd_bsize / DEV_BSIZE;
1073 
1074         bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1075         bp->b_data = (caddr_t)finfo;
1076 
1077 #ifdef DEBUG
1078 	printf("fdformat: blkno %x count %x\n", bp->b_blkno, bp->b_bcount);
1079 #endif
1080 
1081         /* now do the format */
1082         fdstrategy(bp);
1083 
1084         /* ...and wait for it to complete */
1085         s = splbio();
1086         while(!(bp->b_flags & B_DONE))
1087         {
1088                 rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 0);
1089                 if(rv == EWOULDBLOCK)
1090 		    /*break*/;
1091         }
1092         splx(s);
1093 
1094         if(rv == EWOULDBLOCK) {
1095                 /* timed out */
1096                 rv = EIO;
1097 		/* XXX what to do to the buf? it will eventually fall
1098 		   out as finished, but ... ?*/
1099 		/*biodone(bp);*/
1100 	}
1101         if(bp->b_flags & B_ERROR)
1102                 rv = bp->b_error;
1103         free(bp, M_TEMP);
1104         return rv;
1105 }
1106