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