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