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