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