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