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