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