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