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