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