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